Java Question Compiling Jars for Libraries

bloxa69

Active Member
Licensed User
Longtime User
In my quest for hardware accelerated live wallpaper i started playing with different existing B4A libraries. As the first step in the learning process I was able to decompile them, create new packages and classes in Eclipse, paste the code, build the pathes and then recompile new jars. All my new libs i messed with in that way worked the same as original B4A jars.
Now, i tried to do the same thing with Erels Live Wallpaper library and got null pointer errors when trying to use my new recompiled jar instead of the original. In B4A IDE I don't get any errors and get all properties and methods just like in the original library. I only get null pointer errors while running the app on device. The app code is exactly the same, i just switch libraries in IDE.
I didn't change the library code in any way and both jars seem exactly the same to me, though I didn't do a full comparison check. I am attaching the zip with 2 libraries - the original and mine. Mine is called lwp.jar. If anybody could tell me why one is working (the original) and another is not (lwp.jar) i would greatly appreciate it.
Thanks in advance.
 
Last edited:

bloxa69

Active Member
Licensed User
Longtime User
OK, now I a did full comparison check and found some differences which from the Java's point of view should be the same things, so I think those differences shouldn't cause any problems.
Examples:
B4X:
'original code:

'code removed as per thedesolatesoul suggestion

Technically, those are identical pieces of code, just formatted in a slightly different way.

Also, I've tried opening the original LWP library and my copy in Winrar and drag and drop the classes from Erel's jar to mine and after that my library would start working. Sometimes it was enough just to replace B4AEngine class with the original one from Erel's jar and that would fix my library.

I cannot find any explanation for any of this, unless Erel's jar is modified in some way to protect the library from being copied, modified and reused?
 
Last edited:

thedesolatesoul

Expert
Licensed User
Longtime User
a) You should not post code (jars) that you dont have permission to (I dont know if you took Erel's permission to post the jar)
b) jd-gui is not perfect
c) You maybe missing some annotations like @ActivityObject or something like that.
d) You will soon find that this method of learning is extremely frustrating but good luck.
 

bloxa69

Active Member
Licensed User
Longtime User
Hey, thedesolatesoul, thanks a lot for a quick reply and for advice.


c) You maybe missing some annotations like @ActivityObject or something like that.

Not really, I did a full comparison check and my jar is an exact copy of the original jar, codewise.

a) You should not post code (jars) that you dont have permission to (I dont know if you took Erel's permission to post the jar)

Removed the zip with jars just in case. My personal opinion - this is a jar that every registered user has access to, so I don't see why it cannot be posted (only registered users can download it). I think it's also inlcuded in the B4A demo version that anybody can download and play with. But still, I removed it. Probably, nobody would bother with it anyway. Questions over email are not recommended, so I didn't bother Erel directly in that regard.

If you guys think the piece of code that i quoted from that jar cannot be posted too, please let me know and i'll take it off as well. Although I've seen many quotes from the libraries on this forum and I am sure nobody was asking for permission before doing that, but I could be mistaken. I apologize then just in case.

d) You will soon find that this method of learning is extremely frustrating but good luck.

Sofar I found it the only productive method to get closer to wrapping external libraries. It worked for me until I got to Erel's library. I would prefer not doing it at all and not to reinvent the wheel, but there is no tutorials for wrapping libraries and no hardware accelerated Live Wallpaper Library, so I needed to do it on my own and start somewhere. As a first step I had to make sure the compiling process was right and I am not missing anything in that area. This way I could be sure if my wrapper doesn't work, that's not related to the compiling process but to the code itself.

A question before I went too far and got in trouble (again):
Correct me if I'm wrong, but I think I can modify the libraries I get with the software I paid for, and use the modified versions in my own apps without any additional permissions from the developer (Erel in that case). I think as long as I don't post the modified libraries anywhere, don't sell or don't distribute the libraries, I'm safe without asking for any permissions and as long as I don't pretend to be the author of the library.
I didn't post any modified code and didn't plan to.

Another question(s):
I couldn't find (maybe didn't look too hard) any ethics section here and any licensing info in regard to the libraries not included with B4A and posted by other developers for free use.
- Do I need a developer's permission to modify his free library posted on B4A forum and use it for my projects only?
- Do I need a permission to create a wrapper library based on somebody else library posted here for free?
- Do I need the original developer's permission if I modify his library and want to post it here under different name but with the info (attribution) that my library is based on his code?


Thanks again for a quick reply.
 

thedesolatesoul

Expert
Licensed User
Longtime User
I think it's also inlcuded in the B4A demo version that anybody can download and play with.
The Demo/Trial version cannot use libraries.

If you guys think the piece of code that i quoted from that jar cannot be posted too, please let me know and i'll take it off as well. Although I've seen many quotes from the libraries on this forum and I am sure nobody was asking for permission before doing that, but I could be mistaken. I apologize then just in case.
I'd play safe: http://www.b4x.com/forum/basic4android-updates-questions/12409-ongoing-notification-2.html#post86789

Correct me if I'm wrong, but I think I can modify the libraries I get with the software I paid for, and use the modified versions in my own apps without any additional permissions from the developer (Erel in that case). I think as long as I don't post the modified libraries anywhere, don't sell or don't distribute the libraries, I'm safe without asking for any permissions and as long as I don't pretend to be the author of the library.
I didn't post any modified code and didn't plan to.
Do you see anywhere in the licence that says you may modify the libraries or even decompile them? I havent read anywhere.

I couldn't find (maybe didn't look too hard) any ethics section here and any licensing info in regard to the libraries not included with B4A and posted by other developers for free use.
- Do I need a developer's permission to modify his free library posted on B4A forum and use it for my projects only?
- Do I need a permission to create a wrapper library based on somebody else library posted here for free?
- Do I need the original developer's permission if I modify his library and want to post it here under different name but with the info (attribution) that my library is based on his code?
Read here: http://www.b4x.com/forum/libraries-...important-notice-about-libraries-license.html
You should be careful about which libraries you wrap as well as they may have difference licences and you may not be allowed to use it in commercial applications.
I would say, if in doubt, ask the library developer, it wont hurt and he may be willing to help you.

If you post your jar with your code, I would be willing to test it and see what is wrong with it.
 

bloxa69

Active Member
Licensed User
Longtime User
Hey, thedesolatesoul, thanks for the info, nice chat:sign0188:

Let's leave Erel's library aside as it's a part of his commercial software, and I was playing with it just for my own amusement, as a learning exercise. I even didn't modify it, just tried to use it to test how my Eclipse compiling process works, to know what problems to expect down the road. I think that's legal.

If I ever do anything with it I definitely ask Erel. I already asked him about adding hardware acceleration to LWP, but he wasn't very enthusiastic about it, so I started trying it on my own, just to see if it's even possible in B4A with my level of Java.

Do you see anywhere in the licence that says you may modify the libraries or even decompile them? I havent read anywhere.

CC license allows just that. And that's what most additional B4A libraries use by default, per Erel.
Creative Commons

CC Attribution 3.0 -
You are free:
to Share — to copy, distribute and transmit the work
to Remix — to adapt the work (hence decompile, rewrite the code, do anything you can think of)
to make commercial use of the work (you can even sell it, modified or not)

All you have to do is to give author the credit, hence attribution in the way he specified in his library. If he did not, then it's up to you how to credit the author. No permissions of any kind needed.


P.S.
Besides all that copyright scare, I still didn't get an answer in regard to why two seemingly identical jar libraries don't work in the same way in B4A.
:sign0163: (please?)
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Note that the EULA included with Basic4android doesn't allow you to reverse engineer the software (including the libraries).

However you should just ask ;) as I usually don't mind publishing the sources. Especially when it allows other developers to extend the functionality and upload modified libraries.

B4X:
package anywheresoftware.b4a.objects;

import java.util.ArrayList;

import android.app.WallpaperManager;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.service.wallpaper.WallpaperService;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BA.Events;
import anywheresoftware.b4a.BA.Hide;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.BA.Version;
import anywheresoftware.b4a.keywords.Common;
import anywheresoftware.b4a.objects.drawable.CanvasWrapper;
import anywheresoftware.b4a.objects.drawable.CanvasWrapper.BitmapWrapper;
import anywheresoftware.b4a.objects.drawable.CanvasWrapper.RectWrapper;

@Hide
public class WallpaperInternalService extends WallpaperService{

   @Override
   public void onCreate() {
      super.onCreate();
      try {
         Intent i = new Intent(this, Class.forName(getPackageName() + ".wallpaperservice"));
         startService(i);
      } catch (ClassNotFoundException e) {
         Common.Log("WallpaperService not found.");
         throw new RuntimeException(e);
      }
   }
   @Override
   public Engine onCreateEngine() {
      LWEngine l = new LWEngine();
      B4AEngine b = new B4AEngine(l);
      l.engine = b;
      b.setTouchEventsEnabled(LWManager.acceptTouch);
      LWManager.engines.add(l);
      return b;
   }
   /**
    * Manages the wallpaper events and the timer.
    *A tutorial is available <link>here|http://www.b4x.com/forum/basic4android-getting-started-tutorials/12605-android-live-wallpaper-tutorial.html</link>.
    */
   @Events(values={
         "SizeChanged (Engine As LWEngine)",
         "Touch (Engine As LWEngine, Action As Int, X As Float, Y As Float)",
         "VisibilityChanged (Engine As LWEngine, Visible As Boolean)",
         "EngineDestroyed (Engine As LWEngine)",
         "Tick (Engine As LWEngine)",
         "OffsetChanged (Engine As LWEngine)"
   })
   @Version(1.01f)
   @ShortName("LWManager")
   public static class LWManager {
      private static String eventName;
      private static BA ba;
      static ArrayList<LWEngine> engines = new ArrayList<LWEngine>();
      static int interval;
      static boolean atLeastOneVisible = false;
      static boolean acceptTouch;
      
      /**
       * Initializes the object.
       *EventName - Sets the Subs that will handle the events.
       *TouchEventsEnabled - Whether the wallpaper should raise the Touch event when the user touches the screen.
       */
      public static void Initialize(String EventName, boolean TouchEventsEnabled, BA ba) {
         if (ba.sharedProcessBA == null || ba.sharedProcessBA.isService == false) {
            throw new RuntimeException("LWManager can only be added to a service.");
         }
         acceptTouch = TouchEventsEnabled;
         LWManager.ba = ba;
         LWManager.eventName = EventName.toLowerCase(BA.cul);
      }
      /**
       * Starts the internal timer.
       *IntervalMs - Interval in milliseconds.
       */
      public static void StartTicking(int IntervalMs) {
         interval = IntervalMs;
         if (TickTack.isQueued == false) {
            TickTack tt = new TickTack();
            BA.handler.postDelayed(tt, interval);
         }
      }
      /**
       * Stops the internal timer.
       */
      public static void StopTicking() {
         interval = 0;
      }
      static void raiseEvent(String event, Object... params) {
         ba.raiseEvent(null, eventName + "_" + event, params);
      }
      static void tick() {
         for (LWEngine e : engines) {
            if (e.engine.isVisible() == true) {
               ba.raiseEvent(null, eventName + "_tick", e);
            }
         }
      }
      static void checkIfThereIsAtLeastOneVisible() {
         if (interval == 0)
            return;
         atLeastOneVisible = false;
         for (LWEngine e : engines) {
            if (e.engine.isVisible() == true) {
               atLeastOneVisible = true;
               break;
            }
         }
         if (atLeastOneVisible) {
            StartTicking(interval);
         }
      }


      static class TickTack implements Runnable {
         static boolean isQueued;
         @Override
         public void run() {
            if (interval == 0 || atLeastOneVisible == false) {
               isQueued = false;
               return;      
            }
            isQueued = true;
            BA.handler.postDelayed(this,interval);
            tick();
         }
      }

   }
   /**
    * Represents a wallpaper instance.
    *A tutorial is available <link>here|http://www.b4x.com/forum/basic4android-getting-started-tutorials/12605-android-live-wallpaper-tutorial.html</link>.
    */
   @ShortName("LWEngine")
   public static class LWEngine {
      B4AEngine engine;
      /**
       * Gets or sets the Tag value. This is a place holder which can used to store additional data.
       */
      public Object Tag;
      /**
       * A convenient Rect object which you can use. This object is not used internally.
       */
      public RectWrapper Rect = new RectWrapper();
      /**
       * Tests whether this wallpaper is running in "preview mode".
       */
      public boolean getIsPreview() {
         return engine.isPreview();
      }
      /**
       * Tests whether this wallpaper is visible.
       */
      public boolean getIsVisible() {
         return engine.isVisible();
      }
      public LWEngine() {
         Rect.Initialize(0, 0, 0, 0);
      }
      /**
       * Returns the canvas which is used to draw on the wallpaper.
       *Changes will not be visible till you call Refresh or RefreshAll.
       */
      public CanvasWrapper getCanvas() {
         return engine.cw;
      }
      /**
       * Refreshes the complete screen.
       */
      public void RefreshAll() {
         Refresh(engine.all);
      }
      /**
       * Refreshes the given region.
       */
      public void Refresh(Rect DirtyRect) {
         SurfaceHolder sh = engine.getSurfaceHolder();
         Canvas c = sh.lockCanvas(DirtyRect);
         if (c == null) {
            Common.Log("Null canvas returned.");
            return;
         }
         try {
            c.drawBitmap(engine.bg, DirtyRect, DirtyRect, null);
         }
         finally {
            sh.unlockCanvasAndPost(c);
         }
      }
      /**
       * Tests whether this object is initialized.
       */
      public boolean IsInitialized() {
         return engine != null;
      }
      /**
       * Returns the current horizontal offset related to the full wallpaper width.
       */
      public int getCurrentOffsetX() {
         return engine.offsetX;
      }
      /**
       * Returns the current vertical offset related to the full wallpaper height.
       */
      public int getCurrentOffsetY() {
         return engine.offsetY;
      }
      /**
       * Returns the screen width.
       */
      public int getScreenWidth() {
         return engine.width;
      }
      /**
       * Returns the screen height.
       */
      public int getScreenHeight() {
         return engine.height;
      }
      /**
       * Returns the full wallpaper width. A wallpaper can be made of several screens.
       */
      public int getFullWallpaperWidth() {
         return engine.fullWidth;
      }
      /**
       * Returns the full wallpaper height.
       */
      public int getFullWallpaperHeight() {
         return engine.fullHeight;
      }

   }

   @Hide
   public class B4AEngine extends Engine {
      private LWEngine lw;
      Rect all = new Rect(0, 0, 0, 0);
      Bitmap bg;
      CanvasWrapper cw = new CanvasWrapper();
      int offsetX, offsetY;
      int fullWidth, fullHeight;
      int width, height;
      public B4AEngine(LWEngine l) {
         lw = l;
      }

      @Override
      public void onVisibilityChanged(boolean visible) {
         LWManager.checkIfThereIsAtLeastOneVisible();
         LWManager.raiseEvent("visibilitychanged", lw, visible);
      }

      @Override
      public void onTouchEvent(MotionEvent event) {
         LWManager.raiseEvent("touch", lw, event.getAction(), event.getX(), event.getY());          
      }

      @Override
      public void onOffsetsChanged(float xOffset, float yOffset,
            float xOffsetStep, float yOffsetStep,
            int xPixelOffset, int yPixelOffset) {
         offsetX = -xPixelOffset;
         offsetY = -yPixelOffset;
         LWManager.raiseEvent("offsetchanged", lw);
         
      }

      @Override
      public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
         if (bg != null)
            bg.recycle();
         BitmapWrapper bw = new BitmapWrapper();
         bw.InitializeMutable(width, height);
         bg = bw.getObject();
         cw.Initialize2(bg);
         this.width = width;
         this.height = height;
         all.right = width;
         all.bottom = height;
         fullWidth = WallpaperManager.getInstance(BA.applicationContext).getDesiredMinimumWidth();
         fullHeight = WallpaperManager.getInstance(BA.applicationContext).getDesiredMinimumHeight();
         LWManager.raiseEvent("sizechanged", lw);
      }
      
      @Override
      public void onDestroy() {
         LWManager.raiseEvent("enginedestroyed", lw);
         LWManager.engines.remove(lw);
      }

   }

}

Besides all that copyright scare, I still didn't get an answer in regard to why two seemingly identical jar libraries don't work in the same way in B4A.
Because they are not identical. Decompilers are not perfect.
 

bloxa69

Active Member
Licensed User
Longtime User
Erel,
thanks a lot for the source, it compiles fine now. Yes, after looking at the source and JD GUI output, I see the difference. That completes my first grade in Java school.
Now I'll try to modify the code and see what happens.
I plan to add getWallpaperInfo() and find a way to work with COMMAND_TAP and COMMAND_SECONDARY_TAP, as I don't want the live wallpaper to do anything when user taps the icon, not empty area. Current touch event fires even when you touch an icon on the screen.
Thanks for sharing the code.
 
Top