add presenters to aidl.

Change-Id: I7c3187a5f619f9dd49104b3a131696a32248eb85
diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp
index 3590255..9415bc8 100755
--- a/tools/aidl/Type.cpp
+++ b/tools/aidl/Type.cpp
@@ -26,13 +26,9 @@
 Type* MAP_TYPE;
 Type* LIST_TYPE;
 Type* CLASSLOADER_TYPE;
-Type* RPC_SERVICE_BASE_TYPE;
 Type* RPC_DATA_TYPE;
-Type* RPC_BROKER_TYPE;
-Type* RPC_ENDPOINT_INFO_TYPE;
-Type* RPC_RESULT_HANDLER_TYPE;
 Type* RPC_ERROR_TYPE;
-Type* RPC_ERROR_LISTENER_TYPE;
+Type* EVENT_FAKE_TYPE;
 
 Expression* NULL_VALUE;
 Expression* THIS_VALUE;
@@ -124,32 +120,15 @@
     CONTEXT_TYPE = new Type("android.content", "Context", Type::BUILT_IN, false, false, false);
     NAMES.Add(CONTEXT_TYPE);
 
-    RPC_SERVICE_BASE_TYPE = new Type("com.android.athome.service", "AndroidAtHomeService",
-                                    Type::BUILT_IN, false, false, false);
-    NAMES.Add(RPC_SERVICE_BASE_TYPE);
-
     RPC_DATA_TYPE = new RpcDataType();
     NAMES.Add(RPC_DATA_TYPE);
 
-    RPC_BROKER_TYPE = new Type("com.android.athome.utils", "AndroidAtHomeBroker",
-                                    Type::BUILT_IN, false, false, false);
-    NAMES.Add(RPC_BROKER_TYPE);
-
-    RPC_ENDPOINT_INFO_TYPE = new ParcelableType("com.android.athome.rpc", "EndpointInfo",
-                                    true, __FILE__, __LINE__);
-    NAMES.Add(RPC_ENDPOINT_INFO_TYPE);
-
-    RPC_RESULT_HANDLER_TYPE = new ParcelableType("com.android.athome.rpc", "RpcResultHandler",
-                                    true, __FILE__, __LINE__);
-    NAMES.Add(RPC_RESULT_HANDLER_TYPE);
-
     RPC_ERROR_TYPE = new ParcelableType("com.android.athome.rpc", "RpcError",
                                     true, __FILE__, __LINE__);
     NAMES.Add(RPC_ERROR_TYPE);
 
-    RPC_ERROR_LISTENER_TYPE = new Type("com.android.athome.rpc", "RpcErrorHandler",
-                                    Type::BUILT_IN, false, false, false);
-    NAMES.Add(RPC_ERROR_LISTENER_TYPE);
+    EVENT_FAKE_TYPE = new Type("event", Type::BUILT_IN, false, false, false);
+    NAMES.Add(EVENT_FAKE_TYPE);
 
     CLASSLOADER_TYPE = new ClassLoaderType();
     NAMES.Add(CLASSLOADER_TYPE);
diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h
index fa57840..c7b2e5d 100755
--- a/tools/aidl/Type.h
+++ b/tools/aidl/Type.h
@@ -535,13 +535,9 @@
 
 extern Type* CONTEXT_TYPE;
 
-extern Type* RPC_SERVICE_BASE_TYPE;
 extern Type* RPC_DATA_TYPE;
-extern Type* RPC_BROKER_TYPE;
-extern Type* RPC_ENDPOINT_INFO_TYPE;
-extern Type* RPC_RESULT_HANDLER_TYPE;
 extern Type* RPC_ERROR_TYPE;
-extern Type* RPC_ERROR_LISTENER_TYPE;
+extern Type* EVENT_FAKE_TYPE;
 
 extern Expression* NULL_VALUE;
 extern Expression* THIS_VALUE;
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index c39e603..ab9a245 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -419,11 +419,19 @@
         return err;
     }
 
-    if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel()
-                : returnType->CanWriteToRpcData())) {
-        fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
-                    m->type.type.lineno, m->type.type.data);
-        err = 1;
+    if (returnType == EVENT_FAKE_TYPE) {
+        if (kind != INTERFACE_TYPE_RPC) {
+            fprintf(stderr, "%s:%d event methods only supported for rpc interfaces\n",
+                    filename, m->type.type.lineno);
+            err = 1;
+        }
+    } else {
+        if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel()
+                    : returnType->CanWriteToRpcData())) {
+            fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
+                        m->type.type.lineno, m->type.type.data);
+            err = 1;
+        }
     }
 
     if (m->type.dimension > 0 && !returnType->CanBeArray()) {
@@ -455,6 +463,14 @@
             err = 1;
             goto next;
         }
+
+        if (t == EVENT_FAKE_TYPE) {
+            fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n",
+                    filename, m->type.type.lineno, arg->name.data, index,
+                    arg->type.type.data);
+            err = 1;
+            goto next;
+        }
         
         if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
             fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
@@ -505,7 +521,7 @@
         // check that the name doesn't match a keyword
         if (matches_keyword(arg->name.data)) {
             fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
-                    " Java keyword\n",
+                    " Java or aidl keyword\n",
                     filename, m->name.lineno, index, arg->name.data);
             err = 1;
         }
diff --git a/tools/aidl/generate_java_rpc.cpp b/tools/aidl/generate_java_rpc.cpp
index 53a11f2..d705c79 100644
--- a/tools/aidl/generate_java_rpc.cpp
+++ b/tools/aidl/generate_java_rpc.cpp
@@ -7,6 +7,26 @@
 
 Type* SERVICE_CONTAINER_TYPE = new Type("com.android.athome.service",
         "AndroidAtHomeServiceContainer", Type::BUILT_IN, false, false, false);
+Type* PRESENTER_BASE_TYPE = new Type("com.android.athome.service",
+        "AndroidAtHomePresenter", Type::BUILT_IN, false, false, false);
+Type* PRESENTER_LISTENER_BASE_TYPE = new Type("com.android.athome.service",
+        "AndroidAtHomePresenter.Listener", Type::BUILT_IN, false, false, false);
+Type* RPC_BROKER_TYPE = new Type("com.android.athome.utils", "AndroidAtHomeBroker",
+        Type::BUILT_IN, false, false, false);
+Type* RPC_SERVICE_BASE_TYPE = new Type("com.android.athome.service", "AndroidAtHomeService",
+        Type::BUILT_IN, false, false, false);
+Type* RPC_SERVICE_INFO_TYPE = new ParcelableType("com.android.athome.stubs",
+        "AndroidAtHomeServiceInfo", true, __FILE__, __LINE__);
+Type* RPC_RESULT_HANDLER_TYPE = new ParcelableType("com.android.athome.rpc", "RpcResultHandler",
+        true, __FILE__, __LINE__);
+Type* RPC_ERROR_LISTENER_TYPE = new Type("com.android.athome.rpc", "RpcErrorHandler",
+        Type::BUILT_IN, false, false, false);
+
+static void generate_create_from_data(Type* t, StatementBlock* addTo, const string& key,
+        Variable* v, Variable* data, Variable** cl);
+static void generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from);
+static void generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data);
 
 static string
 format_int(int n)
@@ -27,6 +47,226 @@
     }
 }
 
+static string
+results_class_name(const string& n)
+{
+    string str = n;
+    str[0] = toupper(str[0]);
+    str.insert(0, "On");
+    return str;
+}
+
+static string
+results_method_name(const string& n)
+{
+    string str = n;
+    str[0] = toupper(str[0]);
+    str.insert(0, "on");
+    return str;
+}
+
+static string
+push_method_name(const string& n)
+{
+    string str = n;
+    str[0] = toupper(str[0]);
+    str.insert(0, "push");
+    return str;
+}
+
+// =================================================
+class DispatcherClass : public Class
+{
+public:
+    DispatcherClass(const interface_type* iface, Expression* target);
+    virtual ~DispatcherClass();
+
+    void AddMethod(const method_type* method);
+    void DoneWithMethods();
+
+    Method* processMethod;
+    Variable* actionParam;
+    Variable* requestParam;
+    Variable* errorParam;
+    Variable* requestData;
+    Variable* resultData;
+    IfStatement* dispatchIfStatement;
+    Expression* targetExpression;
+
+private:
+    void generate_process();
+};
+
+DispatcherClass::DispatcherClass(const interface_type* iface, Expression* target)
+    :Class(),
+     dispatchIfStatement(NULL),
+     targetExpression(target)
+{
+    generate_process();
+}
+
+DispatcherClass::~DispatcherClass()
+{
+}
+
+void
+DispatcherClass::generate_process()
+{
+    // byte[] process(String action, byte[] params, RpcError status)
+    this->processMethod = new Method;
+        this->processMethod->modifiers = PUBLIC;
+        this->processMethod->returnType = BYTE_TYPE;
+        this->processMethod->returnTypeDimension = 1;
+        this->processMethod->name = "process";
+        this->processMethod->statements = new StatementBlock;
+
+    this->actionParam = new Variable(STRING_TYPE, "action");
+    this->processMethod->parameters.push_back(this->actionParam);
+
+    this->requestParam = new Variable(BYTE_TYPE, "requestParam", 1);
+    this->processMethod->parameters.push_back(this->requestParam);
+
+    this->errorParam = new Variable(RPC_ERROR_TYPE, "errorParam", 0);
+    this->processMethod->parameters.push_back(this->errorParam);
+
+    this->requestData = new Variable(RPC_DATA_TYPE, "request");
+    this->processMethod->statements->Add(new VariableDeclaration(requestData,
+                new NewExpression(RPC_DATA_TYPE, 1, this->requestParam)));
+
+    this->resultData = new Variable(RPC_DATA_TYPE, "resultData");
+    this->processMethod->statements->Add(new VariableDeclaration(this->resultData,
+                NULL_VALUE));
+}
+
+void
+DispatcherClass::AddMethod(const method_type* method)
+{
+    arg_type* arg;
+
+    // The if/switch statement
+    IfStatement* ifs = new IfStatement();
+        ifs->expression = new MethodCall(new StringLiteralExpression(method->name.data), "equals",
+                1, this->actionParam);
+    StatementBlock* block = ifs->statements = new StatementBlock;
+    if (this->dispatchIfStatement == NULL) {
+        this->dispatchIfStatement = ifs;
+        this->processMethod->statements->Add(dispatchIfStatement);
+    } else {
+        this->dispatchIfStatement->elseif = ifs;
+        this->dispatchIfStatement = ifs;
+    }
+    
+    // The call to decl (from above)
+    MethodCall* realCall = new MethodCall(this->targetExpression, method->name.data);
+
+    // args
+    Variable* classLoader = NULL;
+    VariableFactory stubArgs("_arg");
+    arg = method->args;
+    while (arg != NULL) {
+        Type* t = NAMES.Search(arg->type.type.data);
+        Variable* v = stubArgs.Get(t);
+        v->dimension = arg->type.dimension;
+
+        // Unmarshall the parameter
+        block->Add(new VariableDeclaration(v));
+        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
+            generate_create_from_data(t, block, arg->name.data, v,
+                    this->requestData, &classLoader);
+        } else {
+            if (arg->type.dimension == 0) {
+                block->Add(new Assignment(v, new NewExpression(v->type)));
+            }
+            else if (arg->type.dimension == 1) {
+                generate_new_array(v->type, block, v, this->requestData);
+            }
+            else {
+                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
+                        __LINE__);
+            }
+        }
+
+        // Add that parameter to the method call
+        realCall->arguments.push_back(v);
+
+        arg = arg->next;
+    }
+
+
+    Type* returnType = NAMES.Search(method->type.type.data);
+    if (returnType == EVENT_FAKE_TYPE) {
+        returnType = VOID_TYPE;
+    }
+    
+    // the real call
+    bool first = true;
+    Variable* _result = NULL;
+    if (returnType == VOID_TYPE) {
+        block->Add(realCall);
+    } else {
+        _result = new Variable(returnType, "_result",
+                                method->type.dimension);
+        block->Add(new VariableDeclaration(_result, realCall));
+
+        // need the result RpcData
+        if (first) {
+            block->Add(new Assignment(this->resultData,
+                        new NewExpression(RPC_DATA_TYPE)));
+            first = false;
+        }
+
+        // marshall the return value
+        generate_write_to_data(returnType, block,
+                new StringLiteralExpression("_result"), _result, this->resultData);
+    }
+
+    // out parameters
+    int i = 0;
+    arg = method->args;
+    while (arg != NULL) {
+        Type* t = NAMES.Search(arg->type.type.data);
+        Variable* v = stubArgs.Get(i++);
+
+        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+            // need the result RpcData
+            if (first) {
+                block->Add(new Assignment(this->resultData, new NewExpression(RPC_DATA_TYPE)));
+                first = false;
+            }
+
+            generate_write_to_data(t, block, new StringLiteralExpression(arg->name.data),
+                    v, this->resultData);
+        }
+
+        arg = arg->next;
+    }
+}
+
+void
+DispatcherClass::DoneWithMethods()
+{
+    if (this->dispatchIfStatement == NULL) {
+        return;
+    }
+
+    this->elements.push_back(this->processMethod);
+
+    IfStatement* fallthrough = new IfStatement();
+        fallthrough->statements = new StatementBlock;
+        fallthrough->statements->Add(new ReturnStatement(
+                    new MethodCall(SUPER_VALUE, "process", 3, this->actionParam, this->requestParam,
+                        this->errorParam)));
+    this->dispatchIfStatement->elseif = fallthrough;
+    IfStatement* s = new IfStatement;
+        s->statements = new StatementBlock;
+    this->processMethod->statements->Add(s);
+    s->expression = new Comparison(this->resultData, "!=", NULL_VALUE);
+    s->statements->Add(new ReturnStatement(new MethodCall(this->resultData, "serialize")));
+    s->elseif = new IfStatement;
+    s = s->elseif;
+    s->statements->Add(new ReturnStatement(NULL_VALUE));
+}
+
 // =================================================
 class RpcProxyClass : public Class
 {
@@ -53,7 +293,7 @@
     this->context = new Variable(CONTEXT_TYPE, "_context");
     this->elements.push_back(new Field(PRIVATE, this->context));
     // endpoint
-    this->endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "_endpoint");
+    this->endpoint = new Variable(RPC_SERVICE_INFO_TYPE, "_endpoint");
     this->elements.push_back(new Field(PRIVATE, this->endpoint));
 
     // methods
@@ -68,10 +308,10 @@
 RpcProxyClass::generate_ctor()
 {
     Variable* context = new Variable(CONTEXT_TYPE, "context");
-    Variable* endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "endpoint");
+    Variable* endpoint = new Variable(RPC_SERVICE_INFO_TYPE, "endpoint");
     Method* ctor = new Method;
         ctor->modifiers = PUBLIC;
-        ctor->name = this->type->Name();
+        ctor->name = class_name_leaf(this->type->Name());
         ctor->statements = new StatementBlock;
         ctor->parameters.push_back(context);
         ctor->parameters.push_back(endpoint);
@@ -82,43 +322,120 @@
 }
 
 // =================================================
-class ServiceBaseClass : public Class
+class PresenterClass : public DispatcherClass
+{
+public:
+    PresenterClass(const interface_type* iface, Type* listenerType);
+    virtual ~PresenterClass();
+
+    Variable* _listener;
+
+private:
+    void generate_ctor();
+};
+
+Expression*
+generate_get_listener_expression(Type* cast)
+{
+    return new Cast(cast, new MethodCall(THIS_VALUE, "getView"));
+}
+
+PresenterClass::PresenterClass(const interface_type* iface, Type* listenerType)
+    :DispatcherClass(iface, generate_get_listener_expression(listenerType))
+{
+    this->modifiers = PRIVATE;
+    this->what = Class::CLASS;
+    this->type = new Type(iface->package ? iface->package : "",
+                        append(iface->name.data, ".Presenter"),
+                        Type::GENERATED, false, false, false);
+    this->extends = PRESENTER_BASE_TYPE;
+
+    this->_listener = new Variable(listenerType, "_listener");
+
+    // methods
+    generate_ctor();
+}
+
+PresenterClass::~PresenterClass()
+{
+}
+
+void
+PresenterClass::generate_ctor()
+{
+    Variable* context = new Variable(CONTEXT_TYPE, "context");
+    Variable* endpoint = new Variable(RPC_SERVICE_INFO_TYPE, "endpoint");
+    Variable* listener = new Variable(this->_listener->type, "listener");
+    Method* ctor = new Method;
+        ctor->modifiers = PUBLIC;
+        ctor->name = class_name_leaf(this->type->Name());
+        ctor->statements = new StatementBlock;
+        ctor->parameters.push_back(context);
+        ctor->parameters.push_back(endpoint);
+        ctor->parameters.push_back(listener);
+    this->elements.push_back(ctor);
+
+    ctor->statements->Add(new MethodCall("super", 3, context, endpoint, listener));
+    ctor->statements->Add(new Assignment(this->_listener, listener));
+}
+
+// =================================================
+class ListenerClass : public Class
+{
+public:
+    ListenerClass(const interface_type* iface);
+    virtual ~ListenerClass();
+
+    bool needed;
+
+private:
+    void generate_ctor();
+};
+
+ListenerClass::ListenerClass(const interface_type* iface)
+    :Class(),
+     needed(false)
+{
+    this->comment = "/** Extend this to listen to the events from this class. */";
+    this->modifiers = STATIC | PUBLIC ;
+    this->what = Class::CLASS;
+    this->type = new Type(iface->package ? iface->package : "",
+                        append(iface->name.data, ".Listener"),
+                        Type::GENERATED, false, false, false);
+    this->extends = PRESENTER_LISTENER_BASE_TYPE;
+}
+
+ListenerClass::~ListenerClass()
+{
+}
+
+// =================================================
+class ServiceBaseClass : public DispatcherClass
 {
 public:
     ServiceBaseClass(const interface_type* iface);
     virtual ~ServiceBaseClass();
 
-    void AddMethod(const string& methodName, StatementBlock** statements);
-    void DoneWithMethods();
-
     bool needed;
-    Method* processMethod;
-    Variable* actionParam;
-    Variable* requestParam;
-    Variable* errorParam;
-    Variable* requestData;
-    Variable* resultData;
-    IfStatement* dispatchIfStatement;
 
 private:
     void generate_ctor();
-    void generate_process();
 };
 
 ServiceBaseClass::ServiceBaseClass(const interface_type* iface)
-    :Class(),
-     needed(false),
-     dispatchIfStatement(NULL)
+    :DispatcherClass(iface, THIS_VALUE),
+     needed(false)
 {
     this->comment = "/** Extend this to implement a link service. */";
     this->modifiers = STATIC | PUBLIC | ABSTRACT;
     this->what = Class::CLASS;
-    this->type = NAMES.Find(iface->package, append(iface->name.data, ".ServiceBase").c_str());
+    this->type = new Type(iface->package ? iface->package : "",
+                        append(iface->name.data, ".ServiceBase"),
+                        Type::GENERATED, false, false, false);
     this->extends = RPC_SERVICE_BASE_TYPE;
 
     // methods
     generate_ctor();
-    generate_process();
 }
 
 ServiceBaseClass::~ServiceBaseClass()
@@ -145,71 +462,6 @@
     ctor->statements->Add(new MethodCall("super", 4, container, name, type, version));
 }
 
-void
-ServiceBaseClass::generate_process()
-{
-    // byte[] process(String action, byte[] params, RpcError status)
-    this->processMethod = new Method;
-        this->processMethod->modifiers = PUBLIC;
-        this->processMethod->returnType = BYTE_TYPE;
-        this->processMethod->returnTypeDimension = 1;
-        this->processMethod->name = "process";
-        this->processMethod->statements = new StatementBlock;
-    this->elements.push_back(this->processMethod);
-
-    this->actionParam = new Variable(STRING_TYPE, "action");
-    this->processMethod->parameters.push_back(this->actionParam);
-
-    this->requestParam = new Variable(BYTE_TYPE, "requestParam", 1);
-    this->processMethod->parameters.push_back(this->requestParam);
-
-    this->errorParam = new Variable(RPC_ERROR_TYPE, "errorParam", 0);
-    this->processMethod->parameters.push_back(this->errorParam);
-
-    this->requestData = new Variable(RPC_DATA_TYPE, "request");
-    this->processMethod->statements->Add(new VariableDeclaration(requestData,
-                new NewExpression(RPC_DATA_TYPE, 1, this->requestParam)));
-
-    this->resultData = new Variable(RPC_DATA_TYPE, "resultData");
-    this->processMethod->statements->Add(new VariableDeclaration(this->resultData,
-                NULL_VALUE));
-}
-
-void
-ServiceBaseClass::AddMethod(const string& methodName, StatementBlock** statements)
-{
-    IfStatement* ifs = new IfStatement();
-        ifs->expression = new MethodCall(new StringLiteralExpression(methodName), "equals", 1,
-                this->actionParam);
-        ifs->statements = *statements = new StatementBlock;
-    if (this->dispatchIfStatement == NULL) {
-        this->dispatchIfStatement = ifs;
-        this->processMethod->statements->Add(dispatchIfStatement);
-    } else {
-        this->dispatchIfStatement->elseif = ifs;
-        this->dispatchIfStatement = ifs;
-    }
-}
-
-void
-ServiceBaseClass::DoneWithMethods()
-{
-    IfStatement* fallthrough = new IfStatement();
-        fallthrough->statements = new StatementBlock;
-        fallthrough->statements->Add(new ReturnStatement(
-                    new MethodCall(SUPER_VALUE, "process", 3, this->actionParam, this->requestParam,
-                        this->errorParam)));
-    this->dispatchIfStatement->elseif = fallthrough;
-    IfStatement* s = new IfStatement;
-        s->statements = new StatementBlock;
-    this->processMethod->statements->Add(s);
-    s->expression = new Comparison(this->resultData, "!=", NULL_VALUE);
-    s->statements->Add(new ReturnStatement(new MethodCall(this->resultData, "serialize")));
-    s->elseif = new IfStatement;
-    s = s->elseif;
-    s->statements->Add(new ReturnStatement(NULL_VALUE));
-}
-
 // =================================================
 class ResultDispatcherClass : public Class
 {
@@ -262,7 +514,7 @@
     Variable* callbackParam = new Variable(OBJECT_TYPE, "cbObj");
     Method* ctor = new Method;
         ctor->modifiers = PUBLIC;
-        ctor->name = this->type->Name();
+        ctor->name = class_name_leaf(this->type->Name());
         ctor->statements = new StatementBlock;
         ctor->parameters.push_back(methodIdParam);
         ctor->parameters.push_back(callbackParam);
@@ -348,24 +600,6 @@
 }
 
 // =================================================
-static string
-results_class_name(const string& n)
-{
-    string str = n;
-    str[0] = toupper(str[0]);
-    str.insert(0, "On");
-    return str;
-}
-
-static string
-results_method_name(const string& n)
-{
-    string str = n;
-    str[0] = toupper(str[0]);
-    str.insert(0, "on");
-    return str;
-}
-
 static Type*
 generate_results_method(const method_type* method, RpcProxyClass* proxyClass)
 {
@@ -526,118 +760,13 @@
 }
 
 static void
-generate_service_base_methods(const method_type* method, ServiceBaseClass* serviceBaseClass)
-{
-    arg_type* arg;
-    StatementBlock* block;
-    serviceBaseClass->AddMethod(method->name.data, &block);
-
-    // The abstract method that the service developers implement
-    Method* decl = new Method;
-        decl->comment = gather_comments(method->comments_token->extra);
-        decl->modifiers = PUBLIC | ABSTRACT;
-        decl->returnType = NAMES.Search(method->type.type.data);
-        decl->returnTypeDimension = method->type.dimension;
-        decl->name = method->name.data;
-
-    arg = method->args;
-    while (arg != NULL) {
-        decl->parameters.push_back(new Variable(
-                            NAMES.Search(arg->type.type.data), arg->name.data,
-                            arg->type.dimension));
-        arg = arg->next;
-    }
-
-    serviceBaseClass->elements.push_back(decl);
-    
-    // The call to decl (from above)
-    MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);
-    
-    // args
-    Variable* classLoader = NULL;
-    VariableFactory stubArgs("_arg");
-    arg = method->args;
-    while (arg != NULL) {
-        Type* t = NAMES.Search(arg->type.type.data);
-        Variable* v = stubArgs.Get(t);
-        v->dimension = arg->type.dimension;
-
-        // Unmarshall the parameter
-        block->Add(new VariableDeclaration(v));
-        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
-            generate_create_from_data(t, block, arg->name.data, v,
-                    serviceBaseClass->requestData, &classLoader);
-        } else {
-            if (arg->type.dimension == 0) {
-                block->Add(new Assignment(v, new NewExpression(v->type)));
-            }
-            else if (arg->type.dimension == 1) {
-                generate_new_array(v->type, block, v, serviceBaseClass->requestData);
-            }
-            else {
-                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
-                        __LINE__);
-            }
-        }
-
-        // Add that parameter to the method call
-        realCall->arguments.push_back(v);
-
-        arg = arg->next;
-    }
-
-    // the real call
-    bool first = true;
-    Variable* _result = NULL;
-    if (0 == strcmp(method->type.type.data, "void")) {
-        block->Add(realCall);
-    } else {
-        _result = new Variable(decl->returnType, "_result",
-                                decl->returnTypeDimension);
-        block->Add(new VariableDeclaration(_result, realCall));
-
-        // need the result RpcData
-        if (first) {
-            block->Add(new Assignment(serviceBaseClass->resultData,
-                        new NewExpression(RPC_DATA_TYPE)));
-            first = false;
-        }
-
-        // marshall the return value
-        generate_write_to_data(decl->returnType, block,
-                new StringLiteralExpression("_result"), _result, serviceBaseClass->resultData);
-    }
-
-    // out parameters
-    int i = 0;
-    arg = method->args;
-    while (arg != NULL) {
-        Type* t = NAMES.Search(arg->type.type.data);
-        Variable* v = stubArgs.Get(i++);
-
-        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
-            // need the result RpcData
-            if (first) {
-                block->Add(new Assignment(serviceBaseClass->resultData,
-                            new NewExpression(RPC_DATA_TYPE)));
-                first = false;
-            }
-
-
-            generate_write_to_data(t, block, new StringLiteralExpression(arg->name.data),
-                    v, serviceBaseClass->resultData);
-        }
-
-        arg = arg->next;
-    }
-}
-
-static void
-generate_method(const method_type* method, RpcProxyClass* proxyClass,
+generate_regular_method(const method_type* method, RpcProxyClass* proxyClass,
         ServiceBaseClass* serviceBaseClass, ResultDispatcherClass* resultsDispatcherClass,
         int index)
 {
-    // == the callback interface for results =================================
+    arg_type* arg;
+
+    // == the callback interface for results ================================
     // the service base class
     Type* resultsInterfaceType = generate_results_method(method, proxyClass);
     
@@ -650,8 +779,132 @@
                 index);
     }
 
+    // == The abstract method that the service developers implement ==========
+    Method* decl = new Method;
+        decl->comment = gather_comments(method->comments_token->extra);
+        decl->modifiers = PUBLIC | ABSTRACT;
+        decl->returnType = NAMES.Search(method->type.type.data);
+        decl->returnTypeDimension = method->type.dimension;
+        decl->name = method->name.data;
+    arg = method->args;
+    while (arg != NULL) {
+        decl->parameters.push_back(new Variable(
+                            NAMES.Search(arg->type.type.data), arg->name.data,
+                            arg->type.dimension));
+        arg = arg->next;
+    }
+    serviceBaseClass->elements.push_back(decl);
+    
+
     // == the dispatch method in the service base class ======================
-    generate_service_base_methods(method, serviceBaseClass);
+    serviceBaseClass->AddMethod(method);
+}
+
+static void
+generate_event_method(const method_type* method, RpcProxyClass* proxyClass,
+        ServiceBaseClass* serviceBaseClass, ListenerClass* listenerClass,
+        PresenterClass* presenterClass, int index)
+{
+    arg_type* arg;
+    listenerClass->needed = true;
+
+    // == the push method in the service base class =========================
+    Method* push = new Method;
+        push->modifiers = PUBLIC;
+        push->name = push_method_name(method->name.data);
+        push->statements = new StatementBlock;
+        push->returnType = VOID_TYPE;
+    serviceBaseClass->elements.push_back(push);
+
+    // The local variables
+    Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
+    push->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
+
+    // Add the arguments
+    arg = method->args;
+    while (arg != NULL) {
+        // Function signature
+        Type* t = NAMES.Search(arg->type.type.data);
+        Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+        push->parameters.push_back(v);
+
+        // Input parameter marshalling
+        generate_write_to_data(t, push->statements,
+                new StringLiteralExpression(arg->name.data), v, _data);
+
+        arg = arg->next;
+    }
+
+    // Send the notifications
+    push->statements->Add(new MethodCall("pushEvent", 2,
+                new StringLiteralExpression(method->name.data),
+                new MethodCall(_data, "serialize")));
+
+    // == the event callback dispatcher method  ====================================
+    presenterClass->AddMethod(method);
+
+    // == the event method in the listener base class =====================
+    Method* event = new Method;
+        event->modifiers = PUBLIC;
+        event->name = method->name.data;
+        event->statements = new StatementBlock;
+        event->returnType = VOID_TYPE;
+    listenerClass->elements.push_back(event);
+    arg = method->args;
+    while (arg != NULL) {
+        event->parameters.push_back(new Variable(
+                            NAMES.Search(arg->type.type.data), arg->name.data,
+                            arg->type.dimension));
+        arg = arg->next;
+    }
+}
+
+static void
+generate_listener_methods(RpcProxyClass* proxyClass, Type* presenterType, Type* listenerType)
+{
+    // AndroidAtHomePresenter _presenter;
+    // void registerListener(Listener listener) {
+    //     unregisterListener();
+    //     _presenter = new Presenter(_context, _endpoint, listener);
+    //     _presenter.attachToModel();
+    // }
+    // void unregisterListener() {
+    //     if (_presenter != null) {
+    //         _presenter.detachFromModel();
+    //     }
+    // }
+
+    Variable* _presenter = new Variable(presenterType, "_presenter");
+    proxyClass->elements.push_back(new Field(PRIVATE, _presenter));
+
+    Variable* listener = new Variable(listenerType, "listener");
+
+    Method* registerMethod = new Method;
+        registerMethod->modifiers = PUBLIC;
+        registerMethod->returnType = VOID_TYPE;
+        registerMethod->name = "registerListener";
+        registerMethod->statements = new StatementBlock;
+        registerMethod->parameters.push_back(listener);
+    proxyClass->elements.push_back(registerMethod);
+
+    registerMethod->statements->Add(new MethodCall(THIS_VALUE, "unregisterListener"));
+    registerMethod->statements->Add(new Assignment(_presenter, new NewExpression(presenterType,
+                    3, proxyClass->context, proxyClass->endpoint, listener)));
+    registerMethod->statements->Add(new MethodCall(_presenter, "attachToModel"));
+
+    Method* unregisterMethod = new Method;
+        unregisterMethod->modifiers = PUBLIC;
+        unregisterMethod->returnType = VOID_TYPE;
+        unregisterMethod->name = "unregisterListener";
+        unregisterMethod->statements = new StatementBlock;
+    proxyClass->elements.push_back(unregisterMethod);
+
+    IfStatement* ifst = new IfStatement;
+        ifst->expression = new Comparison(_presenter, "!=", NULL_VALUE);
+    unregisterMethod->statements->Add(ifst);
+
+    ifst->statements->Add(new MethodCall(_presenter, "detachFromModel"));
+    ifst->statements->Add(new Assignment(_presenter, NULL_VALUE));
 }
 
 Class*
@@ -662,6 +915,12 @@
         NAMES.Find(iface->package, iface->name.data));
     RpcProxyClass* proxy = new RpcProxyClass(iface, interfaceType);
 
+    // the listener class
+    ListenerClass* listener = new ListenerClass(iface);
+
+    // the presenter class
+    PresenterClass* presenter = new PresenterClass(iface, listener->type);
+
     // the service base class
     ServiceBaseClass* base = new ServiceBaseClass(iface);
     proxy->elements.push_back(base);
@@ -674,17 +933,27 @@
     interface_item_type* item = iface->interface_items;
     while (item != NULL) {
         if (item->item_type == METHOD_TYPE) {
-            generate_method((method_type*)item, proxy, base, results, index);
+            if (NAMES.Search(((method_type*)item)->type.type.data) == EVENT_FAKE_TYPE) {
+                generate_event_method((method_type*)item, proxy, base, listener, presenter, index);
+            } else {
+                generate_regular_method((method_type*)item, proxy, base, results, index);
+            }
         }
         item = item->next;
         index++;
     }
+    presenter->DoneWithMethods();
     base->DoneWithMethods();
 
     // only add this if there are methods with results / out parameters
     if (results->needed) {
         proxy->elements.push_back(results);
     }
+    if (listener->needed) {
+        proxy->elements.push_back(listener);
+        proxy->elements.push_back(presenter);
+        generate_listener_methods(proxy, presenter->type, listener->type);
+    }
 
     return proxy;
 }