1 // Copyright 2019 The Amber Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <android/log.h>
16 #include <android/looper.h>
17 #include <android_native_app_glue.h>
18
19 #include "amber/amber.h"
20 #include "amber/recipe.h"
21 #include "amber/result.h"
22 #include "amber_script.h"
23
24 namespace {
25
26 // TODO(jaebaek): Change this as a method rather than macro.
27 // Android log function wrappers
28 const char* kTAG = "Amber";
29 #define LOGE(...) \
30 ((void)__android_log_print(ANDROID_LOG_ERROR, kTAG, __VA_ARGS__))
31
amber_sample_main(android_app * app)32 void amber_sample_main(android_app* app) {
33 amber::android::AmberScriptLoader loader(app);
34
35 amber::Result r = loader.LoadAllScriptsFromAsset();
36 if (!r.IsSuccess()) {
37 LOGE("%s", r.Error().c_str());
38 return;
39 }
40
41 const auto& script_info = loader.GetScripts();
42
43 std::vector<std::string> failures;
44 for (const auto& info : script_info) {
45 LOGE("\ncase %s: run...", info.asset_name.c_str());
46
47 amber::Amber am;
48 amber::Recipe recipe;
49 amber::Result r = am.Parse(info.script_content, &recipe);
50 if (!r.IsSuccess()) {
51 LOGE("\ncase %s: fail\n\t%s", info.asset_name.c_str(), r.Error().c_str());
52 failures.push_back(info.asset_name);
53 continue;
54 }
55
56 amber::Options amber_options;
57 r = am.ExecuteWithShaderData(&recipe, amber_options, info.shader_map);
58 if (!r.IsSuccess()) {
59 LOGE("\ncase %s: fail\n\t%s", info.asset_name.c_str(), r.Error().c_str());
60 failures.push_back(info.asset_name);
61 continue;
62 }
63
64 LOGE("\ncase %s: pass", info.asset_name.c_str());
65 }
66
67 if (!failures.empty()) {
68 LOGE("\nSummary of Failures:");
69 for (const auto& failure : failures)
70 LOGE("%s", failure.c_str());
71 }
72 LOGE("\nsummary: %u pass, %u fail",
73 static_cast<uint32_t>(script_info.size() - failures.size()),
74 static_cast<uint32_t>(failures.size()));
75 }
76
77 // Process the next main command.
handle_cmd(android_app * app,int32_t cmd)78 void handle_cmd(android_app* app, int32_t cmd) {
79 switch (cmd) {
80 case APP_CMD_INIT_WINDOW:
81 amber_sample_main(app);
82 break;
83 case APP_CMD_TERM_WINDOW:
84 break;
85 default:
86 break;
87 }
88 }
89
90 } // namespace
91
android_main(struct android_app * app)92 void android_main(struct android_app* app) {
93 // Set the callback to process system events
94 app->onAppCmd = handle_cmd;
95
96 // Used to poll the events in the main loop
97 android_poll_source* source;
98
99 // Main loop
100 while (app->destroyRequested == 0) {
101 auto result = ALooper_pollOnce(1, nullptr, nullptr, (void**)&source);
102 if (result == ALOOPER_POLL_ERROR) {
103 LOGE("ALooper_pollOnce returned an error.");
104 exit(1);
105 }
106
107 if (result >= 0 && source != nullptr) {
108 source->process(app, source);
109 }
110 }
111 }
112