11package com .example .buttonapp ;
22
3- import android .os .Bundle ;
4- import android .widget .Button ;
5- import android .widget .Toast ;
6- import androidx .appcompat .app .AppCompatActivity ;
7- import java .io .IOException ;
8- import okhttp3 .Call ;
9- import okhttp3 .Callback ;
10- import okhttp3 .OkHttpClient ;
11- import okhttp3 .Request ;
3+ import android .os .Bundle ;
4+ import android .view .ViewGroup ;
5+ import android .widget .Button ;
6+ import android .widget .LinearLayout ;
7+ import androidx .appcompat .app .AlertDialog ;
8+ import androidx .appcompat .app .AppCompatActivity ;
9+ import com .google .gson .Gson ;
10+ import com .google .gson .annotations .SerializedName ;
11+ import java .io .BufferedReader ;
12+ import java .io .IOException ;
13+ import java .io .InputStream ;
14+ import java .io .InputStreamReader ;
15+ import java .nio .charset .StandardCharsets ;
16+ import java .util .HashMap ;
17+ import java .util .Map ;
18+ import okhttp3 .Call ;
19+ import okhttp3 .Callback ;
20+ import okhttp3 .Headers ;
21+ import okhttp3 .MediaType ;
22+ import okhttp3 .OkHttpClient ;
23+ import okhttp3 .Request ;
24+ import okhttp3 .RequestBody ;
1225import okhttp3 .Response ;
1326
1427public class MainActivity extends AppCompatActivity {
1528
1629 private final OkHttpClient client = new OkHttpClient ();
17- // 10.0.2.2 is how the Android Emulator sees your computer's localhost
18- private final String SERVER_URL = "http://10.0.2.2:8080/" ;
30+ private LinearLayout buttonContainer ;
31+ private final Gson gson = new Gson ();
32+
33+ private static class ButtonSpec {
34+ @ SerializedName ("title" )
35+ String title ;
36+ @ SerializedName ("request" )
37+ String request ;
38+ }
1939
2040 @ Override
2141 protected void onCreate (Bundle savedInstanceState ) {
2242 super .onCreate (savedInstanceState );
2343 setContentView (R .layout .activity_main );
44+ buttonContainer = findViewById (R .id .buttonContainer );
45+
46+ String buttonsJson = readAssetToString ("buttons.json" );
47+ ButtonSpec [] specs = gson .fromJson (buttonsJson , ButtonSpec [].class );
48+ if (specs != null ) {
49+ for (ButtonSpec s : specs ) {
50+ Button b = new Button (this );
51+ b .setText (s .title );
52+ LinearLayout .LayoutParams lp = new LinearLayout .LayoutParams (
53+ ViewGroup .LayoutParams .MATCH_PARENT ,
54+ ViewGroup .LayoutParams .WRAP_CONTENT );
55+ lp .setMargins (0 , 16 , 0 , 0 );
56+ b .setLayoutParams (lp );
57+ b .setOnClickListener (v -> onButtonClick (s .request ));
58+ buttonContainer .addView (b );
59+ }
60+ }
61+ }
62+
63+ private String readAssetToString (String name ) {
64+ try (InputStream is = getAssets ().open (name );
65+ InputStreamReader isr = new InputStreamReader (is , StandardCharsets .UTF_8 );
66+ BufferedReader br = new BufferedReader (isr )) {
67+ StringBuilder sb = new StringBuilder ();
68+ String line ;
69+ while ((line = br .readLine ()) != null ) {
70+ sb .append (line ).append ('\n' );
71+ }
72+ return sb .toString ();
73+ } catch (IOException e ) {
74+ e .printStackTrace ();
75+ return "" ;
76+ }
77+ }
78+
79+ private void onButtonClick (String requestHeading ) {
80+ new Thread (() -> {
81+ String httpText = readAssetToString ("requests.http" );
82+ Map <String , String > vars = parseHttpFileVariables (httpText );
83+ String block = extractRequestBlock (httpText , requestHeading );
84+ if (block == null ) {
85+ runOnUiThread (() -> showAlert ("Error" , "Request not found: " + requestHeading ));
86+ return ;
87+ }
88+ Request okReq = buildOkHttpRequestFromBlock (block , vars );
89+ if (okReq == null ) {
90+ runOnUiThread (() -> showAlert ("Error" , "Failed to build request" ));
91+ return ;
92+ }
93+ client .newCall (okReq ).enqueue (new Callback () {
94+ @ Override
95+ public void onFailure (Call call , IOException e ) {
96+ runOnUiThread (() -> showAlert ("Network Error" , e .getMessage ()));
97+ }
98+
99+ @ Override
100+ public void onResponse (Call call , Response response ) throws IOException {
101+ final String body = response .body () != null ? response .body ().string () : "" ;
102+ runOnUiThread (() -> showAlert ("Response: " + response .code (), body ));
103+ }
104+ });
105+ }).start ();
106+ }
24107
25- Button btnOne = findViewById (R .id .btn_one );
26- Button btnTwo = findViewById (R .id .btn_two );
108+ private Map <String , String > parseHttpFileVariables (String text ) {
109+ Map <String , String > vars = new HashMap <>();
110+ BufferedReader br = new BufferedReader (new InputStreamReader (
111+ new java .io .ByteArrayInputStream (text .getBytes (StandardCharsets .UTF_8 )),
112+ StandardCharsets .UTF_8 ));
113+ try {
114+ String line ;
115+ while ((line = br .readLine ()) != null ) {
116+ line = line .trim ();
117+ if (line .startsWith ("@" )) {
118+ int eq = line .indexOf ('=' );
119+ if (eq > 1 ) {
120+ String name = line .substring (1 , eq ).trim ();
121+ String val = line .substring (eq + 1 ).trim ();
122+ vars .put (name , val );
123+ }
124+ }
125+ }
126+ } catch (IOException ignored ) { }
127+ return vars ;
128+ }
27129
28- btnOne .setOnClickListener (v -> makeRequest ("button1" ));
29- btnTwo .setOnClickListener (v -> makeRequest ("button2" ));
130+ private String extractRequestBlock (String text , String heading ) {
131+ String [] lines = text .split ("\\ r?\\ n" );
132+ StringBuilder sb = null ;
133+ for (int i = 0 ; i < lines .length ; i ++) {
134+ if (lines [i ].trim ().equals (heading )) {
135+ sb = new StringBuilder ();
136+ for (int j = i + 1 ; j < lines .length ; j ++) {
137+ if (lines [j ].trim ().startsWith ("### " )) break ;
138+ sb .append (lines [j ]).append ('\n' );
139+ }
140+ break ;
141+ }
142+ }
143+ return sb == null ? null : sb .toString ().trim ();
30144 }
31145
32- private void makeRequest (String path ) {
33- Request request = new Request .Builder ()
34- .url (SERVER_URL + path )
35- .build ();
146+ private Request buildOkHttpRequestFromBlock (String block , Map <String , String > vars ) {
147+ BufferedReader br = new BufferedReader (new InputStreamReader (
148+ new java .io .ByteArrayInputStream (block .getBytes (StandardCharsets .UTF_8 )),
149+ StandardCharsets .UTF_8 ));
150+ try {
151+ String methodAndUrl ;
152+ do {
153+ methodAndUrl = br .readLine ();
154+ if (methodAndUrl == null ) return null ;
155+ } while (methodAndUrl .trim ().isEmpty ());
156+
157+ String [] parts = methodAndUrl .trim ().split ("\\ s+" , 2 );
158+ String method = parts [0 ].toUpperCase ();
159+ String url = parts .length > 1 ? substituteVariables (parts [1 ].trim (), vars ) : "" ;
160+
161+ Headers .Builder headersBuilder = new Headers .Builder ();
162+ String line ;
163+ StringBuilder bodySb = new StringBuilder ();
164+ boolean inBody = false ;
165+ while ((line = br .readLine ()) != null ) {
166+ if (!inBody ) {
167+ if (line .trim ().isEmpty ()) {
168+ inBody = true ;
169+ continue ;
170+ }
171+ int colon = line .indexOf (':' );
172+ if (colon > 0 ) {
173+ String name = line .substring (0 , colon ).trim ();
174+ String val = line .substring (colon + 1 ).trim ();
175+ val = substituteVariables (val , vars );
176+ headersBuilder .add (name , val );
177+ }
178+ } else {
179+ bodySb .append (line ).append ('\n' );
180+ }
181+ }
36182
37- client .newCall (request ).enqueue (new Callback () {
38- @ Override
39- public void onFailure (Call call , IOException e ) {
40- runOnUiThread (() ->
41- Toast .makeText (MainActivity .this , "Network Error: " + e .getMessage (), Toast .LENGTH_LONG ).show ());
183+ RequestBody requestBody = null ;
184+ if (!method .equals ("GET" ) && !method .equals ("HEAD" )) {
185+ String bodyStr = bodySb .toString ().trim ();
186+ if (!bodyStr .isEmpty ()) {
187+ String contentType = headersBuilder .build ().get ("Content-Type" );
188+ MediaType mt = contentType != null ? MediaType .parse (contentType ) : MediaType .parse ("application/json; charset=utf-8" );
189+ requestBody = RequestBody .create (bodyStr , mt );
190+ } else {
191+ requestBody = RequestBody .create (new byte [0 ], null );
192+ }
42193 }
43194
44- @ Override
45- public void onResponse (Call call , Response response ) throws IOException {
46- final String responseData = response .isSuccessful () ? "Success!" : "Server Error: " + response .code ();
47- runOnUiThread (() ->
48- Toast .makeText (MainActivity .this , responseData , Toast .LENGTH_SHORT ).show ());
195+ Request .Builder reqB = new Request .Builder ().url (url ).headers (headersBuilder .build ());
196+ switch (method ) {
197+ case "GET" : reqB .get (); break ;
198+ case "POST" : reqB .post (requestBody ); break ;
199+ case "PUT" : reqB .put (requestBody ); break ;
200+ case "DELETE" :
201+ if (requestBody != null ) reqB .delete (requestBody );
202+ else reqB .delete ();
203+ break ;
204+ case "PATCH" : reqB .patch (requestBody ); break ;
205+ default : return null ;
49206 }
50- });
207+ return reqB .build ();
208+ } catch (IOException e ) {
209+ e .printStackTrace ();
210+ return null ;
211+ }
212+ }
213+
214+ private String substituteVariables (String s , Map <String , String > vars ) {
215+ if (s == null ) return "" ;
216+ java .util .regex .Pattern p = java .util .regex .Pattern .compile ("\\ {\\ {([^}]+)\\ }\\ }" );
217+ java .util .regex .Matcher m = p .matcher (s );
218+ StringBuffer sb = new StringBuffer ();
219+ while (m .find ()) {
220+ String name = m .group (1 ).trim ();
221+ String val = vars .getOrDefault (name , "" );
222+ m .appendReplacement (sb , java .util .regex .Matcher .quoteReplacement (val ));
223+ }
224+ m .appendTail (sb );
225+ return sb .toString ();
51226 }
227+
228+ private void showAlert (String title , String message ) {
229+ new AlertDialog .Builder (this )
230+ .setTitle (title )
231+ .setMessage (message )
232+ .setPositiveButton ("OK" , null )
233+ .show ();
234+ }
235+
52236}
0 commit comments