Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

535
LINES

< > BotCompany Repo | #1014873 // Boot-up code for JavaX/Android (stage 2, JavaX, before logging changes)

JavaX source code (Android) [tags: use-pretranspiled] - run with: the app

Libraryless. Click here for Pure Java version (5338L/37K/129K).

!7

set flag NoAWT. set flag Android. set flag AndroidOnly.

import java.util.*;
import java.util.zip.*;
import java.util.List;
import java.util.regex.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.io.*;
import java.net.*;
import java.lang.reflect.*;
import java.lang.ref.*;
import java.lang.management.*;
import java.security.*;
import java.security.spec.*;
import java.math.*;

import android.widget.*;
import android.view.*;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.content.Context;
import android.app.Activity;
import android.view.KeyEvent;
import android.view.inputmethod.*;
import android.content.*;
import android.text.*;

public class main {
  sS awarenessID = #1004078, catEarID = #1014854;
  
  static volatile Class x30;
  static volatile bool x30loading, x30loadingFailed;

  static List<Prog> programsStarted = new ArrayList<Prog>();
  static File defSnip, defargs;
  static volatile Class visibleProgram;
  sbool dontSwitchToRunningProgram;
  static ReliableSingleThread snippetTitleFinder;

  static class Prog {
    String snippetID;
    Thread thread;
  }

  static class Lg {
    static int maxBufferLength = 2048;
    
    Activity context;
    ScrollView sv;
    TextView tv;
    EditText inputView;
    LinearLayout ll;
    StringBuffer buf = new StringBuffer();
    
    Lg(Activity context) {
      this.context = context;
      sv = new ScrollView(context);
      tv = new TextView(context);
      tv.setText(buf.toString());
      sv.addView(tv);
      sv.setLayoutParams(new LinearLayout.LayoutParams(
        LinearLayout.LayoutParams.MATCH_PARENT,
        LinearLayout.LayoutParams.MATCH_PARENT,
        1.0f));
      inputView = new EditText(context);
      inputView.setInputType(InputType.TYPE_CLASS_TEXT); // turn off multiline
      inputView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
          if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) {
            String line = inputView.getText().toString();
            try {
              pout3.write((line + "\n").getBytes("UTF-8"));
              pout3.flush();
            } catch (Exception e) {}
            inputView.selectAll();
          }
          return false;
        }
      });
      ll = new LinearLayout(context);
      ll.setOrientation(ll.VERTICAL);
      ll.addView(sv);
      ll.addView(inputView);
    }
    
    View getView() {
      return ll;
    }
    
    void shortenBuffer() {
      while (buf.length() > maxBufferLength) {
        String s = buf.toString();
        int i = s.indexOf('\n');
        if (i < 0) return;
        buf = new StringBuffer(s.substring(i+1));
      }
    }
    
    // TODO: coalesce
    void print(final String s) {
      androidUI_noWait(r {
        buf.append(s);
        shortenBuffer();
        tv.setText(buf.toString());
        
        sv.post(new Runnable() {
          public void run() {
            // This method works but animates the scrolling 
            // which looks weird on first load
            sv.fullScroll(View.FOCUS_DOWN);

            // This method works even better because there are no animations.
            //sv.scrollTo(0, sv.getBottom());
          }
        });
      });
    }
    
    void println(String s) {
      print(s + "\n");
    }
  }
  
  public static String snippetToRun;
  static TextView statusView;

  public static View main(final Context _context) throws Exception {
    final Activity context = _context instanceof Activity ? (Activity) _context : null;
    
    visibleProgram = null;
    
    //System.out.println("676 context: " + _context);
    androidContext = _context;
    
    if (context == null) { // I guess this is for boot time execution
      if (snippetToRun != null) {
        new Thread() {
          public void run() {
            String[] a = { snippetToRun };
            callx30(a);
          }
        }.start();
      }
      return null;
    }
    
    statusView = aTextView();
    preloadx30();
    while (x30 == null && !x30loading && !x30loadingFailed) sleep(10);

    int nInjections = l(injections());
    if (dontSwitchToRunningProgram)
      dontSwitchToRunningProgram = false;
    else if (nInjections > 0) pcall {
      ret getRunningProgramView(nInjections-1);
    }
    
    prepareOptionsMenu();

    defSnip = new File(userHome(), ".javax/defsnip");
    String id = loadTextFile(defSnip.getPath(), "636");
    defargs = new File(userHome(), ".javax/defargs");
    String arg = loadTextFile(defargs.getPath(), "");

    ScrollView sv = new ScrollView(context);
    LinearLayout ll = new LinearLayout(context);
    ll.setOrientation(LinearLayout.VERTICAL);
    
    ll.addView(statusView);
    
    for i to nInjections: {
      final int _i = i;
      ll.addView(aButton("Back to running program " + (i+1), r { showRunningProgram(_i) }));
    }
    for i to nInjections: {
      final int _i = i;
      ll.addView(aButton("Kill running program " + (i+1), r { killRunningProgram(_i) }));
    }
    
    LinearLayout line1 = new LinearLayout(context);
    line1.addView(aTextView("Snippet ID:"));
    
    final EditText tv = new EditText(context);
    // BAD - tv.setInputType(InputType.TYPE_NUMBER_FLAG_DECIMAL);
    tv.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_CLASS_NUMBER);
    tv.setText(id);
    line1.addView(tv);
    
    snippetTitleFinder = new ReliableSingleThread(r {
      S id = aGetText(tv);
      if (isSnippetID(id))
        aSetText(statusView, snippetTitle(id));
    });
    
    aOnChange(tv, snippetTitleFinder);
    
    Button btnRun = new Button(context);
    btnRun.setText("Run");
    line1.addView(btnRun);
    
    ll.addView(line1);
    
    LinearLayout line2 = new LinearLayout(context);
    
    line2.addView(aTextView("Program arguments:"));
    
    final EditText tvArgs = new EditText(context);
    tvArgs.setText(arg);
    line2.addView(tvArgs);
    
    ll.addView(line2);
    
    LinearLayout line3 = new LinearLayout(context);
    
    /*Button btnLeo = new Button(context);
    btnLeo.setText("Sprechen mit Leo");
    line3.addView(btnLeo);*/
    
    line3.addView(aButton("Cat Ear", r {
      main.run(context, catEarID, new String[0]);
    }));
    
    line3.addView(aButton("Start Awareness [" + awarenessID + "]", r {
      saveDef(awarenessID, "");
      main.run(context, awarenessID, new String[0]);
    }));

    ll.addView(line3);
    
    btnRun.setOnClickListener(new View.OnClickListener() {
      public void onClick(View v) {
        hideKeyboard(context);
        String snippetID = tv.getText().toString();
        String text = "Running: " + snippetID;
        Toast.makeText(context, text, 2000).show();
        
        saveDef(snippetID, tvArgs.getText().toString());
        
        // TODO: quoted args
        run(context, snippetID, tvArgs.getText().toString().split(" +"));
      }
    });

    // Show initial status for 1 second, then snippet title
    aLater(1000, snippetTitleFinder);
    
    sv.addView(ll);
    return sv;
  }
  
  static void saveDef(String snippetID, String args) {
    try {
      saveTextFile(defSnip.getPath(), snippetID);
      saveTextFile(defargs.getPath(), args);
    } catch (IOException e) {
    }
  }
  
  static Lg lg;
  
  static int systemInPipeSize = 4*1024; // 4 K
  static PipedInputStream pin3;
  static PipedOutputStream pout3;
  
  public static void run(final Activity context, final String mainSnippet, final String[] args) {
    try {
      pin3 = new PipedInputStream(systemInPipeSize);
      pout3 = new PipedOutputStream(pin3);
    } catch (IOException e) {}
    
    lg = new Lg(context);
    
    OutputStream outputStream = new OutputStream() {
      public void write(int b) {
        try {
          lg.print(new String(new byte[] {(byte) b}, "UTF-8")); // This is crap
        } catch (UnsupportedEncodingException e) {}
      }
      
      @Override
      public void write(byte[] b, int off, int len) {
        try {
          lg.print(new String(b, off, len, "UTF-8")); // This is crap
        } catch (UnsupportedEncodingException e) {}
      }
    };
    
    PrintStream ps = new PrintStream(outputStream, true);
    System.setOut(ps);
    System.setErr(ps);
    System.setIn(pin3);

    Prog prog = new Prog();
    prog.snippetID = mainSnippet;

    prog.thread = new Thread() {
      public void run() {
        try {
          String[] a = new String[args.length+1];
          System.arraycopy(args, 0, a, 1, args.length);
          a[0] = mainSnippet;
          callx30(a);
        } catch (Throwable e) {
          System.out.println("Whoa!");
          e.printStackTrace();
        }
      }
    };
    
    programsStarted.add(prog);
    prog.thread.start();
    
    context.setContentView(lg.getView());
  }
  
  static void setContentViewInUIThread(final View view) {
    androidUI(r {
      androidActivity().setContentView(view);
    });
  }
  
  public static void hideKeyboard(Activity context) {   
    View view = context.getCurrentFocus();
    if (view != null) {
        InputMethodManager inputManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        inputManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
    }
  }
  
  static void onActivityResult(int requestCode, int resultCode, Intent data) {
    /* TODO?
    if (x30.mainClass != null)
      x30.call(x30.mainClass, "onActivityResult", requestCode, resultCode, data);*/
  }
  
  static void onPrepareOptionsPanel(View view, Menu menu) {
    /* TODO
    if (x30.mainClass != null)
      x30.call(x30.mainClass, "onPrepareOptionsPanel", view, menu);*/
  }
  
  static boolean onOptionsItemSelected(MenuItem item) {
    /* TODO
    if (x30.mainClass != null)
      return (boolean) x30.call(x30.mainClass, "onOptionsItemSelected", item);*/
    S s = str(item.getTitle());
    print("Item title: " + quote(s));
    if (eq(s, "Settings"))
      showStartScreen();
    else if (eqic(s, "Show Console")) {
      visibleProgram = null;
      androidActivity().setContentView(lg.getView());
    }
    callOpt(visibleProgram, 'onMenuCommand, s);
    true;
  }
  
  static void callx30(S[] args) {
    while (x30 == null)
      if (x30loadingFailed) fail("x30 load failed");
      else sleep(10); // guess it's loading
    print("Calling x30 " + join(" ", args));
    pcall {
      set(x30, "androidContext", androidContext);
      ((ThreadLocal) get(x30, 'onProgramLoad)).set(voidfunc(O paa) {
        visibleProgram = (Class) getOpt(paa, 'mainClass);
        //print("Have visible program: " + visibleProgram);
      });
      callMain(x30, args);
      L injections = injections();
      //visibleProgram = (Class) getOpt(last(injections), 'mainClass); // TODO: imprecise if main program tempers with injections
      //print("Have " + l(injections) + " injections, visibleProgram=" + visibleProgram);
      //print("x30 done");
    }
  }
  
  svoid preloadx30() { thread { getx30(); } }
  
  static void getx30() {
    try {
      S status = "";
      if (x30 != null) status = "Have x30.";
      else {
        O dataStore = null;
        pcall {
          dataStore = Class.forName("de.tinybrain.javax_allperms.DataStore");
        }
        if (dataStore != null) {
          x30 = (Class) call(dataStore, "get", "x30");
          if (x30 != null) status = "Have x30 from data store.";
        }
        if (x30 == null) {
          x30loading = true;
          status("Loading x30");
          Class x30 = loadx30("#1004182");
          callOpt(dataStore, "put", "x30", x30);
          setOpt(x30, "bootUpClass", main.class);
          main.x30 = x30;
          status = "x30 loaded.";
        }
      }
      L injections = injections();
      if (nempty(injections))
        status += " " + n2(injections, "injection");
      status(status);
    } catch e {
      printStackTrace(e);
      x30loadingFailed = true;
    } finally {
      x30loading = false;
    }
  }
  
  static L injections() {
    ret (L) callOpt(x30, 'getInjections);
  }
  
  svoid killRunningProgram(int i) {
    try {
      O paa = get(injections(), i);
      if (paa == null) ret;
      call(x30, 'removeInjection, paa);
      showStartScreen();
    } catch e {
      printStackTrace(e);
      status(str(e));
    }
  }
  
  svoid showStartScreen() {
    androidUI(r {
      dontSwitchToRunningProgram = true;
      androidActivity().setContentView(main(androidContext()));
    });
  }
  
  svoid showRunningProgram(int i) {
    View v = getRunningProgramView(i);
    if (v != null)
      setContentViewInUIThread(v);
  }
  
  static View getRunningProgramView(int i) {
    O paa = get(injections(), i);
    if (paa == null) ret null with status("No running program to show");
    Class mainClass = cast getOpt(paa, 'mainClass);
    View view = cast getOpt(mainClass, 'androidShow_view);
    if (view == null)
      //ret null with status("Program has no view to show");
      view = lg.getView(); // show log instead
    print("Switched to program " + get(paa, 'progID));
    visibleProgram = mainClass;
    ViewGroup group = (ViewGroup) view.getParent();
    if (group != null)
      group.removeView(view);
    ret view;
  }
  
  svoid status(S s) {
    aSetText(statusView, s);
    print(s);
  }
  
  static Class<?> loadx30(String programID) ctex {
    System.out.println("Program ID: " + programID);
    S url = "http://tinybrain.de:8080/dexcompile.php?id=" + parseSnippetID(programID);
    byte[] dexData = loadBinaryPage(url);
    if (!isDex(dexData))
      throw new RuntimeException("Dex generation error");
    System.out.println("Dex loaded: " + dexData.length + "b");

    File dexDir = makeAndroidTempDir();
    File dexFile = new File(dexDir, System.currentTimeMillis() + ".dex");
    File dexOutputDir = makeAndroidTempDir();

    System.out.println("Saving dex to: " + dexDir.getAbsolutePath());
    try {
      saveBinaryFile(dexFile.getPath(), dexData);
    } catch (Throwable e) {
      System.out.println("Whoa!");
      throw new RuntimeException(e);
    }

    System.out.println("Getting parent class loader.");
    ClassLoader parentClassLoader =
      main.class.getClassLoader().getParent();

    //System.out.println("Making DexClassLoader.");
    //DexClassLoader classLoader = new DexClassLoader(dexFile.getAbsolutePath(), dexOutputDir.getAbsolutePath(), null,
    //  parentClassLoader);
    Class dcl = Class.forName("dalvik.system.DexClassLoader");
    Object classLoader = dcl.getConstructors()[0].newInstance(dexFile.getAbsolutePath(), dexOutputDir.getAbsolutePath(), null,
      parentClassLoader);

    System.out.println("Loading main class.");
    Class<?> theClass = (Class<?>) call(classLoader, "loadClass", "x30");

    System.out.println("Main class loaded.");
    try {
      set(theClass, "androidContext", androidContext);
    } catch (Throwable e) {}

    setVars(theClass, programID);
    hotwire_copyOver(theClass);
    return theClass;
  }
  
  static void setVars(Class<?> theClass, String programID) {
    try {
      set(theClass, "programID", programID);
    } catch (Throwable e) {}

    try {
      set(theClass, "__javax", x30);
    } catch (Throwable e) {}
  }
  
  static String getConsoleOutput() {
    ret lg.buf.toString();
  }
  
  svoid prepareOptionsMenu {
    pcall {
      Menu menu = cast getOpt(androidActivity(), 'optionsMenu);
      if (menu == null) ret;
      if (menu.size() < 2)
        menu.add("Show Console");
    }
  }
}

Author comment

Began life as a copy of #676

download  show line numbers  debug dex  old transpilations   

Travelled to 13 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1014873
Snippet name: Boot-up code for JavaX/Android (stage 2, JavaX, before logging changes)
Eternal ID of this version: #1014873/3
Text MD5: d095c96ea1f225c27fecc6882f154e07
Transpilation MD5: 82a8e459d7faee2ba46c937756307a87
Author: stefan
Category: javax
Type: JavaX source code (Android)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2019-05-20 13:59:59
Source code size: 16236 bytes / 535 lines
Pitched / IR pitched: No / No
Views / Downloads: 292 / 345
Version history: 2 change(s)
Referenced in: [show references]