1515#include < android/log.h>
1616#include < android_native_app_glue.h>
1717#include < stdarg.h>
18+ #include < stdio.h>
19+ #include < cassert>
1820
1921#include " main.h" // NOLINT
2022
@@ -36,11 +38,82 @@ bool ProcessAndroidEvents(int msec) {
3638 return gAppState ->destroyRequested ;
3739}
3840
41+ // Vars that we need available for appending text to the log window:
42+ class TextViewData {
43+ public:
44+ TextViewData ()
45+ : text_view_obj_(0 ),
46+ text_view_class_ (0 ),
47+ string_class_(0 ),
48+ text_view_append_(0 ) {}
49+
50+ ~TextViewData () {
51+ JNIEnv* env = GetJniEnv ();
52+ assert (env);
53+ env->DeleteLocalRef (text_view_obj_);
54+ text_view_obj_ = 0 ;
55+ }
56+
57+ jobject text_view_obj () const { return text_view_obj_; }
58+ void set_text_view_obj (jobject text_view_obj) {
59+ text_view_obj_ = text_view_obj;
60+ }
61+
62+ jclass text_view_class () const { return text_view_class_; }
63+ void set_text_view_class (jclass text_view_class) {
64+ text_view_class_ = text_view_class;
65+ }
66+
67+ jclass string_class () const { return string_class_; }
68+ void set_string_class (jclass string_class) { string_class_ = string_class; }
69+
70+ jmethodID text_view_append () const { return text_view_append_; }
71+ void set_text_view_append (jmethodID text_view_append) {
72+ text_view_append_ = text_view_append;
73+ }
74+
75+ private:
76+ jobject text_view_obj_;
77+ jclass text_view_class_;
78+ jclass string_class_;
79+ jmethodID text_view_append_;
80+ };
81+ TextViewData text_view_data;
82+
83+ // Appends a string to the text view to be displayed.
84+ // Warning - do not put log statements in here. Since the log statement
85+ // mirrors its output to this, trying to call LogMessage from this subroutine
86+ // causes loops and problems.
87+ void AppendTextViewText (const char * text) {
88+ // Abort if the text view hasn't been created yet.
89+ if (text_view_data.text_view_obj () == 0 ) {
90+ return ;
91+ }
92+ JNIEnv* env = GetJniEnv ();
93+ assert (env);
94+
95+ jstring text_string = env->NewStringUTF (text);
96+
97+ env->CallVoidMethod (text_view_data.text_view_obj (),
98+ text_view_data.text_view_append (), text_string);
99+
100+ env->DeleteLocalRef (text_string);
101+ }
102+
39103// Log a message that can be viewed in "adb logcat".
40104int LogMessage (const char * format, ...) {
105+ static const int kLineBufferSize = 100 ;
106+ char buffer[kLineBufferSize + 1 ];
107+
41108 va_list list;
42109 int rc;
43110 va_start (list, format);
111+ int string_len = vsnprintf (buffer, kLineBufferSize , format, list);
112+ // append a linebreak to the buffer:
113+ buffer[string_len] = ' \n ' ;
114+ buffer[string_len + 1 ] = ' \0 ' ;
115+
116+ AppendTextViewText (buffer);
44117 rc = __android_log_vprint (ANDROID_LOG_INFO, FIREBASE_TESTAPP_NAME, format,
45118 list);
46119 va_end (list);
@@ -58,11 +131,87 @@ JNIEnv* GetJniEnv() {
58131// Get the activity.
59132jobject GetActivity () { return gAppState ->activity ->clazz ; }
60133
134+ // Create a text view, inside of a scroll view, inside of a linear layout
135+ // and display them on screen. This is equivalent to the following
136+ // java code:
137+ // private TextView text_view = new TextView(this);
138+ // LinearLayout linear_layout = new LinearLayout(this);
139+ // linear_layout.addView(text);
140+ // Window window = getWindow();
141+ // window.takeSurface(null);
142+ // window.setContentView(linear_layout);
143+ void CreateJavaTextView (android_app* state) {
144+ JNIEnv* env = GetJniEnv ();
145+ assert (env);
146+ // cache these off for later:
147+ text_view_data.set_string_class (env->FindClass (" java/lang/String" ));
148+ text_view_data.set_text_view_class (env->FindClass (" android/widget/TextView" ));
149+ jclass scroll_view_class = env->FindClass (" android/widget/ScrollView" );
150+
151+ text_view_data.set_text_view_append (
152+ env->GetMethodID (text_view_data.text_view_class (), " append" ,
153+ " (Ljava/lang/CharSequence;)V" ));
154+
155+ // Construct a linear layout.
156+ jclass linear_layout_class = env->FindClass (" android/widget/LinearLayout" );
157+ jmethodID linear_layout_constructor = env->GetMethodID (
158+ linear_layout_class, " <init>" , " (Landroid/content/Context;)V" );
159+ jobject linear_layout_obj = env->NewObject (
160+ linear_layout_class, linear_layout_constructor, state->activity ->clazz );
161+
162+ // Construct a scrollview.
163+ jmethodID scroll_view_constructor = env->GetMethodID (
164+ scroll_view_class, " <init>" , " (Landroid/content/Context;)V" );
165+ jobject scroll_view_obj = env->NewObject (
166+ scroll_view_class, scroll_view_constructor, state->activity ->clazz );
167+
168+ // Construct a text view
169+ jmethodID text_view_constructor =
170+ env->GetMethodID (text_view_data.text_view_class (), " <init>" ,
171+ " (Landroid/content/Context;)V" );
172+
173+ text_view_data.set_text_view_obj (
174+ env->NewObject (text_view_data.text_view_class (), text_view_constructor,
175+ state->activity ->clazz ));
176+
177+ // Add the text view to the scroll view
178+ // and the scroll view to the linear layout.
179+ jmethodID view_add_view = env->GetMethodID (linear_layout_class, " addView" ,
180+ " (Landroid/view/View;)V" );
181+ env->CallVoidMethod (linear_layout_obj, view_add_view, scroll_view_obj);
182+ env->CallVoidMethod (scroll_view_obj, view_add_view,
183+ text_view_data.text_view_obj ());
184+
185+ // Add the linear layout to the view.
186+ jclass activity_class = env->FindClass (" android/app/Activity" );
187+ jmethodID activity_get_window =
188+ env->GetMethodID (activity_class, " getWindow" , " ()Landroid/view/Window;" );
189+ jobject window_obj =
190+ env->CallObjectMethod (state->activity ->clazz , activity_get_window);
191+
192+ // Take control of the window and display the linearlayout in it.
193+ jclass window_class = env->FindClass (" android/view/Window" );
194+
195+ jmethodID window_take_surface = env->GetMethodID (
196+ window_class, " takeSurface" , " (Landroid/view/SurfaceHolder$Callback2;)V" );
197+ env->CallVoidMethod (window_obj, window_take_surface, 0 );
198+
199+ jmethodID window_set_content_view = env->GetMethodID (
200+ window_class, " setContentView" , " (Landroid/view/View;)V" );
201+ env->CallVoidMethod (window_obj, window_set_content_view, linear_layout_obj);
202+
203+ // Clean up our local references.
204+ env->DeleteLocalRef (window_obj);
205+ env->DeleteLocalRef (scroll_view_obj);
206+ env->DeleteLocalRef (linear_layout_obj);
207+ }
208+
61209// Execute common_main(), flush pending events and finish the activity.
62210extern " C" void android_main (struct android_app * state) {
63211 int return_value;
64212 gAppState = state;
65213 static const char * argv[] = {FIREBASE_TESTAPP_NAME};
214+ CreateJavaTextView (state);
66215 return_value = common_main (1 , argv);
67216 (void )return_value; // Ignore the return value.
68217 ProcessAndroidEvents (10 );
0 commit comments