Extend Homescreen widgets

XverhelstX

Well-Known Member
Licensed User
Longtime User
Hello everyone,

This question is actually asked to Erel about the homescreen widgets.

Is it possible for me to create a library that interacts with Basic4Android to extend the functions of homescreen widgets?

What i mean is that I still miss some functions like setLayout on runtime, etc., that I can make with a library.

Thanks,
XverhelstX

Sent from my SE Xperia Play using Tapatalk.
 

XverhelstX

Well-Known Member
Licensed User
Longtime User
I don't know, but it should be possible to change the widget position, right?
I just want to change the position y of view x to position z on runtime.

Is this possible?

Am I also in the capacity of using all public methods over here:
RemoteViews | Android Developers

and let them interract with Basic4Android?

XverhelstX
 
Upvote 0

XverhelstX

Well-Known Member
Licensed User
Longtime User
Erel, I really need some help.
I might have found two ways on how to achieve the setLayout, but i'm still struggling with the R.id thing.


1)

B4X:
public void setImageLayout(String Viewname, int Left, int Top, int Width, int Height)  {
      Log.i("B4A","setImageLayout started");
      int id = BA.applicationContext.getResources().getIdentifier(Viewname, "id", BA.applicationContext.getPackageName());
      Log.i("B4A","id: " + id);

      ImageView view = (ImageView)ba.activity.findViewById(id);

      MarginLayoutParams LeftMargin = (MarginLayoutParams) view.getLayoutParams();
      LeftMargin.leftMargin = Left;

      view.setLayoutParams(LeftMargin);
      
   }

But this gives me an error and id: 0.
So I don't know how I can get the view in another way.


2) Remove the old view and add a new view.

Please, any help?

XverhelstX
 
Upvote 0

XverhelstX

Well-Known Member
Licensed User
Longtime User
Damn, I really need this feature.
Can I ask on how you work with your widget by only giving the widget viewname? Do you work with the R.id to catch and work with the views?

e.g in B4A
rv.setBitmap("viewname", bitmap)

if I can find this, I think it will be a lot easier for me to work with it and I might find it.

Some code like this I need:

B4X:
/**
    * Gets the view ID by the viewname.
    * @param rv
    * @param ViewName
    * @return
    */
   public int getViewID(RemoteViews rv, String ViewName) {
      int id = rv.getviewid();
      return id;
   }

and also how to get past this error:

B4X:
rvex.setImageLayout(rv,\
javac 1.6.0_21
src\com\rootsoft\widget\widget2.java:89: inconvertible types
found   : anywheresoftware.b4a.objects.RemoteViewsWrapper
required: android.widget.RemoteViews
_rvex.setImageLayout((android.widget.RemoteViews)(_rv),"imgView",(int)(30),(int)(0),(int)(50),(int)(50));
                                                 ^
1 error

I really hope you can help me out

XverhelstX
 
Last edited:
Upvote 0

corwin42

Expert
Licensed User
Longtime User
Damn, I really need this feature.
Can I ask on how you work with your widget by only giving the widget viewname? Do you work with the R.id to catch and work with the views?

agraham helped me out to set a RichString formatted string to a widget label using the reflection library. I think you can extract your needed information from the following Sub:

B4X:
Sub SetColorLabel(pName As String, pRv As RemoteViews, pText As RichString)
   Dim Obj1 As Reflector
   Dim args(2) As Object
   Dim types(2) As String
   Obj1.Target = pRv ' a RemoteViewsWrapper
   
   ' first we need the Id of the view
   args(0) = Obj1.GetProcessBA("Widget4x1")
   types(0) = "anywheresoftware.b4a.BA"
   args(1) = pName
   types(1) = "java.lang.String"
   args(0) = Obj1.RunMethod4("getIdForView", args, types) ' get the view Id
   types(0) = "java.lang.int"
   ' now the RichText charSequence
   args(1) = pText ' CharSequence
   types(1) = "java.lang.CharSequence"   
   ' now do the dirty work
   Obj1.RunMethod("checkNull") 'does some internal checking and may set current
   Obj1.Target = Obj1.GetField("current") ' a RemoteViews - get this after checkNull
   Obj1.RunMethod4("setTextViewText", args, types)   
End Sub
 
Upvote 0

XverhelstX

Well-Known Member
Licensed User
Longtime User
Thanks a lot Corwin!
This will help my progress a lot!

I'm still stuck though.

B4X:
' first we need the Id of the view
   Dim Obj1 As Reflector
   Dim args(3) As Object
   Dim types(3) As String
   Obj1.Target = rv ' a RemoteViewsWrapper
   args(0) = Obj1.GetProcessBA("Widget2x1")
   types(0) = "anywheresoftware.b4a.BA"
   args(1) = "imgView"
   types(1) = "java.lang.String"
   args(0) = Obj1.RunMethod4("getIdForView", args, types) ' get the view Id
   ToastMessageShow(args(0),True)
    types(0) = "java.lang.int"
   ' now the RichText charSequence
   args(1) = "setX"
   types(1) = "java.lang.String"
   args(2) = 30
   types(2) = "java.lang.Float"
   ' now do the dirty work
   Obj1.RunMethod("checkNull") 'does some internal checking and may set current
   Obj1.Target = Obj1.GetField("current") ' a RemoteViews - get this after checkNull
   Obj1.RunMethod4("setFloat", args, types)

This crashes my app, and I have no idea why.

Thanks,

XverhelstX
 
Upvote 0

XverhelstX

Well-Known Member
Licensed User
Longtime User
I still don't even know why it doesn't work.
I don't even get an error with this code, but nothing happens.

B4X:
Sub setVisiblity(ViewName As String, Visibility As Int)

   ' first we need the Id of the view
   Dim Obj1 As Reflector
   Dim args(2) As Object
   Dim types(2) As String
   Obj1.Target = Widget2x1.rv ' a RemoteViewsWrapper
   
   ' first we need the Id of the view
   args(0) = Obj1.GetProcessBA("Widget2x1")
   types(0) = "anywheresoftware.b4a.BA"
   args(1) = ViewName
   types(1) = "java.lang.String"
   args(0) = Obj1.RunMethod4("getIdForView", args, types) ' get the view Id
   ToastMessageShow(args(0),True)   
   Log(args(0))
   
   types(0) = "java.lang.int"
   ' now the RichText charSequence
   args(1) = Visibility
   types(1) = "java.lang.int"
   ' now do the dirty work
   Obj1.RunMethod("checkNull") 'does some internal checking and may set current
   Obj1.Target = Obj1.GetField("current") ' a RemoteViews - get this after checkNull
   Obj1.RunMethod4("setViewVisibility", args, types)
   ToastMessageShow("Done",True)   

End Sub


Please, any help?

XverhelstX
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
What values are you using for Visibility? Have you called UpdateWidget?

There were a couple of errors with your previous attempt at setFloat.
B4X:
args(2) = 30 ' probably not a float type, go via a float variable to be sure 
types(2) = "java.lang.Float" ' wrong type. It's a primitive not a Float object "java.lang.float"
 
Upvote 0

XverhelstX

Well-Known Member
Licensed User
Longtime User
Oh thanks a lot Agraham!
Stupid me, I forgot to call rv.UpdateWidget. Thanks for mentioning this!

It works fine now.
I used 0 (visible), 4(invisible) or 8(gone) as the integer values.

There were a couple of errors with your previous attempt at setFloat.

B4X:
args(2) = 30 ' probably not a float type, go via a float variable to be sure 
types(2) = "java.lang.Float" ' wrong type. It's a primitive not a Float object "java.lang.float"

I am basing my self on this:
android - Set position of TextView in RemoteView during runtime - Stack Overflow

so according to that, it says it uses a float value:

B4X:
myRemoteView.setFloat(R.id.myTextView, "setX", 5);

as also in the Android Developers Documentation:

setX (float x)

Since: API Level 11
Sets the visual x position of this view, in pixels.

EDIT: mhmm I just see setx, setTranslationX ans setLeft has been implemented since API level 11, maybe that's because it doesn't work.


Also, could you please take a look here?

http://www.b4x.com/forum/additional...pdates/11820-help-widgetextended-library.html

Because they state that these doesn't work:
B4X:
myRemoteView.setFloat(R.id.myTextView, "setTranslationX", 5); // does not work
myRemoteView.setFloat(R.id.myTextView, "setX", 5); // does not work
myRemoteView.setInt(R.id.myTextView, "setLeft", 5); // does not work

I probably have to use:
B4X:
LayoutParams lp = myRemoteView.getLayoutParams();
lp.marginLeft = 5; 
myRemoteView.setLayoutParams(lp);

in a library then.

I hope you can help me out with this and thank you very much for your explanation.

XverhelstX
 
Last edited:
Upvote 0

agraham

Expert
Licensed User
Longtime User
In Java a "float" is different to a "Float". A float is a primitive numeric type, a Float is a true object boxing a float.

In Java
myRemoteView.setFloat(R.id.myTextView, "setX", 5);
The compiler can upcast the 5 to a float value to satisfy the parameter typing. In reflection it cannot do this so you have to give both the correct type as a parameter as well as informing it what that type actually is so that the correct method signature can be found.

Dim args(2) as Object
Dim f as Float
f = 20
args(1) = f ' will put a Float object, a boxed float, in the Object array
types(1) = "java.lang.float" ' "float" not "Float" - tell it that a primitive is expected in the method signature and it will unbox the supplied Float


As far as I can see a RemoteViews does not have a getLayoutParams method, nor does it inherit one as it extends Object. For security reasons, as they are not running in your process, AppWidgets are highly restricted in what you can do with them.
 
Upvote 0

XverhelstX

Well-Known Member
Licensed User
Longtime User
As far as I can see a RemoteViews does not have a getLayoutParams method, nor does it inherit one as it extends Object. For security reasons, as they are not running in your process, AppWidgets are highly restricted in what you can do with them.

Isn't there then a difference between RemoteViews and Views?
AFAIK, it should be possible to move a view on the panel from a remoteview/widget.

I have an app on my phone where you are able to set the layout of a view (e.g imageview) where you want on the widget.

I want to do the exact same time, I just don't know how.

So I also cannot use setLeft, setX and setTranslationX as they use API 11.

That's why I want to use this:

B4X:
public void setImageLayout(RemoteViews rv, int ViewID, int Left, int Top, int Width, int Height)  {
      
      ImageView view = (ImageView)ba.activity.findViewById(ViewID);

      MarginLayoutParams LeftMargin = (MarginLayoutParams) view.getLayoutParams();
      LeftMargin.leftMargin = Left;

      view.setLayoutParams(LeftMargin);
      //then update the widget
   }

Or do perhaps you have another solution?

Thanks,

XverhelstX
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
Isn't there then a difference between RemoteViews and Views?
There is no relationship at all between a RemoteViews and a View. I'm trying to say this nicely but I think you are biting off a bit more than you can chew with this until you really understand how AppWidgets work (which I also don't by the way :) but I have enough experience to "understand what I don't understand" to paraphrase Donald Rumsfeld).
 
Upvote 0

XverhelstX

Well-Known Member
Licensed User
Longtime User
Well I just thought on the way that Basic4Android does it.

Go to the designer, add a view and that view is displayed on the RemoteView. This way you will be able to control the view on the top layer of the widget. Apparently, I was wrong. :s

I guess i'd have to start reading: http://developer.android.com/reference/android/appwidget/

I'd just know if it is worth the time to get it even to work or Erel might implement it in the next feature.

Thanks a lot though Agraham.

XverhelstX
 
Upvote 0

XverhelstX

Well-Known Member
Licensed User
Longtime User
Erel, do you have any idea if it is possible to do it with Basic4Android?
So to change the position of a view in a remoteviews during runtime either with a library or the reflector library.
Or do I just have to wait to Basic4Android v1.7?

Thanks,
Tomas
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
It doesn't appear to be possible to change the position of a view in an AppWidget once it has been displayed. API level 11 as you observed has some extra setXXX methods but although I can invoke some other methods taking a float like setTextSize using RemoteViews.setFloat, when I substitute these API level 11 additions they don't work and give a "Problem loading Widget" display when invoked on Honeycomb 3.2.1. Looks like something is broken. :(
 
Upvote 0

XverhelstX

Well-Known Member
Licensed User
Longtime User
Ok, thank you so much for trying though Agraham.
I'm still wondering how they achieved do this then though:

https://market.android.com/details?id=com.bitswidget.BITS&feature=search_result

I think the last possibility would be with remoteviews.setInt: setPadding(int, int, int, int)

http://developer.android.com/reference/android/view/View.html#setPadding(int, int, int, int)

To measure its dimensions, a view takes into account its padding. The padding is expressed in pixels for the left, top, right and bottom parts of the view. Padding can be used to offset the content of the view by a specific amount of pixels. For instance, a left padding of 2 will push the view's content by 2 pixels to the right of the left edge. Padding can be set using the setPadding(int, int, int, int) method and queried by calling getPaddingLeft(), getPaddingTop(), getPaddingRight() and getPaddingBottom().

Sincerely,
Tomas
 
Upvote 0
Top