• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

Apps Widget

Magcr23

Lurker
Jan 18, 2017
7
0
Hi, i'm new in this area and i realy could use some help...

I'm trying to create a widget that will show the icon's of some app's installed on the device.

I manage to get a list of packages installed in the device, but i don't know how to get the icon from these.

LoremActivity:

Code:
final static List<String> pacote_app = new ArrayList<String>();
    final List<ApplicationInfo> apps = pm.getInstalledApplications(0);
    for (ApplicationInfo app : apps) {
      //checks for flags; if flagged, check if updated system app
      if ((app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
        // installedApps.add(app);
        //it's a system app, not interested
      } else if ((app.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
        //Discard this one
        //in this case, it should be a user-installed app
      } else {
        String pacote = (String) app.packageName;       //NOME DOS PACOTES

        pacote_app.add(pacote);
      }
    }

    // ATTENTION: This was auto-generated to implement the App Indexing API.
    // See https://g.co/AppIndexing/AndroidStudio for more information.
    client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();

And this in my WidgetViewsFactory:
Code:
import static com.example.magcr23.mywidget.LoremActivity.pacote_app;


public class WidgetViewsFactory implements RemoteViewsService.RemoteViewsFactory {

    Context context;


    private Context ctxt=null;
    private int appWidgetId;

    public WidgetViewsFactory(Context ctxt, Intent intent) {
        this.ctxt=ctxt;
        appWidgetId=intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                AppWidgetManager.INVALID_APPWIDGET_ID);
    }



    @Override
    public void onCreate() {}

    @Override
    public void onDestroy() {
        // no-op
    }

    @Override
    public int getCount() {
        return(pacote_app.size());
    }

    @Override
    public RemoteViews getViewAt(int position) {
        RemoteViews row=new RemoteViews(ctxt.getPackageName(),
                R.layout.list_item);
      

//FILL LIST
        row.setTextViewText(android.R.id.text1, pacote_app.get(position));

//SEND WORD TO ACTIVITY
        Intent i=new Intent();
        Bundle extras=new Bundle();

        extras.putString(WidgetProvider.EXTRA_WORD, pacote_app.get(position));
        i.putExtras(extras);
        row.setOnClickFillInIntent(android.R.id.text1, i);
//--------------
        return(row);
    }

    @Override
    public RemoteViews getLoadingView() {
        return(null);
    }

    @Override
    public int getViewTypeCount() {
        return(1);
    }

    @Override
    public long getItemId(int position) {
        return(position);
    }

    @Override
    public boolean hasStableIds() {
        return(true);
    }

    @Override
    public void onDataSetChanged() {
        // no-op
    }
}


WidgetProvider:
Code:
public class WidgetProvider extends AppWidgetProvider{
    public static String EXTRA_WORD=
            "com.commonsware.android.appwidget.lorem.WORD";
    @Override
    public void onUpdate(Context ctxt, AppWidgetManager appWidgetManager,
                         int[] appWidgetIds) {
        for (int i=0; i<appWidgetIds.length; i++) {
            Intent svcIntent=new Intent(ctxt, WidgetService.class);

            svcIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
            svcIntent.setData(Uri.parse(svcIntent.toUri(Intent.URI_INTENT_SCHEME)));

            RemoteViews widget=new RemoteViews(ctxt.getPackageName(),
                    R.layout.novo_widget);

            widget.setRemoteAdapter(appWidgetIds[i], R.id.listagem,
                    svcIntent);

            Intent clickIntent=new Intent(ctxt, LoremActivity.class);
            PendingIntent clickPI=PendingIntent
                    .getActivity(ctxt, 0,
                            clickIntent,
                            PendingIntent.FLAG_UPDATE_CURRENT);

            widget.setPendingIntentTemplate(R.id.listagem, clickPI);

            appWidgetManager.updateAppWidget(appWidgetIds[i], widget);
        }

        super.onUpdate(ctxt, appWidgetManager, appWidgetIds);
    }
}


WidgetService:
Code:
public class WidgetService extends RemoteViewsService {
    @Override
    public RemoteViewsFactory onGetViewFactory(Intent intent) {
        return(new WidgetViewsFactory(this.getApplicationContext(),
                intent));
    }

Layout:
Code:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="@dimen/widget_margin"
    android:orientation="horizontal">

    <ListView
        android:id="@+id/listagem"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1" />



</LinearLayout>

ListView Layout:
Code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <TextView
        android:id="@android:id/text1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:gravity="center_vertical"
        android:paddingLeft="6dip"
        android:minHeight="?android:attr/listPreferredItemHeight"
        android:textColor="#000"
        />

</LinearLayout>
 
Last edited:

i tried something like the second link, if i use it in a activity (LoremActivity in this case) i can get the icon, but i can't use it in the WidgetViewsFactory, it get's nullExpextionError.
And i don't think it's possible get the icon in the LoremActivity and send it to WidgetViewsFactory, at least i don't know how...
 
Upvote 0
What's LoremActivity, you have not shown that code?

Please show the code you are using to get the icon.

If it causes a nullPointer exception, please show the stacktrace from the Logcat output.

All the code is in my first post, LoremActivity is what i called the activity.

Right now it works like that:
I start the activity to create the array list with the package names and then I create the widget, other wise the array that contains the package names is null and it don't work.
 
Upvote 0
Upvote 0
So, my code is already different in many ways so let's see if i can understand what you mean.

Layout:

Code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">


    <TextView
        android:id="@android:id/text1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:gravity="center_vertical"
        android:paddingLeft="6dip"
        android:minHeight="?android:attr/listPreferredItemHeight"
        android:textColor="#000"
        />


 
    <ImageView
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:padding="3dp"
        app:srcCompat="@drawable/logo"
        android:id="@+id/app_icon"
        android:layout_weight="1"
        android:scaleType="center"
        android:contentDescription="@null"/>

</LinearLayout>

WidgetViewsFactory
Code:
package com.example.magcr23.mywidget;

import static com.example.magcr23.mywidget.LoremActivity.nome_app_HORA;
import static com.example.magcr23.mywidget.LoremActivity.nome_app;



/**
* Created by Magcr23 on 13/01/2017.
*/

public class WidgetViewsFactory implements RemoteViewsService.RemoteViewsFactory {
 

    Context context;
    PackageManager packageManager;


    private Context ctxt=null;
    private int appWidgetId;

    public WidgetViewsFactory(Context ctxt, Intent intent) {
        this.ctxt=ctxt;
        appWidgetId=intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                AppWidgetManager.INVALID_APPWIDGET_ID);
    }



    @Override
    public void onCreate() {
        // NO-OP
    }

    @Override
    public void onDestroy() {
        // NO-OP
    }

    @Override
    public int getCount() {
        return(3);
    }

    @Override
    public RemoteViews getViewAt(final int position) {
        final RemoteViews row=new RemoteViews(ctxt.getPackageName(),
                R.layout.list_item);


//FILL LIST


        try {
            ApplicationInfo app = context.getPackageManager().getApplicationInfo(nome_app_HORA.get(position), 0);
            Drawable icon = packageManager.getApplicationIcon(app);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }


        row.setTextViewText(android.R.id.text1, nome_app_HORA.get(position));


//SEND WORD TO MAIN
        Intent i=new Intent();
        Bundle extras=new Bundle();

        extras.putString(WidgetProvider.EXTRA_WORD, nome_app_HORA.get(position));
        i.putExtras(extras);
        row.setOnClickFillInIntent(android.R.id.text1, i);
//--------------
        return(row);
    }

    @Override
    public RemoteViews getLoadingView() {
        return(null);
    }

    @Override
    public int getViewTypeCount() {
        return(1);
    }

    @Override
    public long getItemId(int position) {
        return(position);
    }

    @Override
    public boolean hasStableIds() {
        return(true);
    }

    @Override
    public void onDataSetChanged() {}

}

So, i can get the icon tough ApplicationInfo, but how can i show it?

I tried:
Code:
View view = null;
        try {
            ApplicationInfo app = context.getPackageManager().getApplicationInfo(nome_app_HORA.get(position), 0);
            Drawable icon = packageManager.getApplicationIcon(app);
            ImageView iconView = (ImageView) view.findViewById(R.id.app_icon);
            iconView.setImageDrawable(icon);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }


And i get this:
Code:
E/AndroidRuntime: FATAL EXCEPTION: Binder_2
    java.lang.NullPointerException
    at com.example.magcr23.mywidget.WidgetViewsFactory.getViewAt(WidgetViewsFactory.java:85)
    at android.widget.RemoteViewsService$RemoteViewsFactoryAdapter.getViewAt(RemoteViewsService.java:164)
    at com.android.internal.widget.IRemoteViewsFactory$Stub.onTransact(IRemoteViewsFactory.java:85)
    at android.os.Binder.execTransact(Binder.java:351)
    at dalvik.system.NativeStart.run(Native Method)
 
Last edited:
Upvote 0
Here's something to think about: In the following code what do you think is the value returned by this.getApplicationContext()?

Code:
public class WidgetService extends RemoteViewsService {
    @Override
    public RemoteViewsFactory onGetViewFactory(Intent intent) {
        return(new WidgetViewsFactory(this.getApplicationContext(),
                intent));
    }

So here's an excercise - put a breakpoint in the constructor of WidgetViewsFactory, and examine the value of the parameter 'ctxt'. I'm guessing that the value is null.
 
Upvote 0
So, i did what you asked and ctxt is not null. an it returns android.app.appliction@41c610d8
However context was null, so i changed everything to ctxt and it worked for while.

In the code:
Code:
View view = null;
        try {
            ApplicationInfo app = ctxt.getPackageManager().getApplicationInfo("com.facebook.katana", 0); //fine
            Drawable icon = ctxt.getPackageManager().getApplicationIcon(app); //fine
            ImageView iconView = (ImageView) view.findViewById(R.id.app_icon); //java.lang.NullPointerException
            iconView.setImageDrawable(icon);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

It gives java.lang.NullPointerException in the line: ImageView iconView = (ImageView) view.findViewById(R.id.app_icon);
I figure that it's because: View view = null;
If i use: View view; it says that view might not have been initialized.
So, how can i make it work? I can't use row.setImageViewIcon() because it asks for an Icon and this "icon" is Drawable.
 
Upvote 0
So this piece of code you show in the previous post. What class and method is that from?
Assuming it's from your Activity. The normal way an Activity is initialised is when the onCreate() method is invoked

Code:
@Override
   public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     view = R.layout.activity_main;
     setContentView(view);
   }

So you can use a class variable called 'view' to store a reference to the Activity's root view.
At the moment you're just initialising it to null, which immediately causes a null pointer exception.
 
Last edited by a moderator:
Upvote 0
I manage to fix this with the following way:
Code:
try {
    ApplicationInfo app = ctxt.getPackageManager().getApplicationInfo(pacote_app2.get(position), 0);
    Drawable icon = ctxt.getPackageManager().getApplicationIcon(app);
    Bitmap bmpIcon = ((BitmapDrawable) icon).getBitmap();
    row.setImageViewBitmap(R.id.app_icon, bmpIcon);

} catch (PackageManager.NameNotFoundException e) {
    e.printStackTrace();
}

But now i noticed another problem...

I have a database that contains every package name installed in the device. With a select i store this data in an array (pacote_nome).
This array is updated every 20 seconds. However, the items in the ListView are not.

This is the code:
Code:
package com.example.magcr23.mywidget;

public class WidgetViewsFactory implements RemoteViewsService.RemoteViewsFactory {



    PackageManager packageManager;


    private Context ctxt;
    private int appWidgetId;

    public WidgetViewsFactory(Context ctxt, Intent intent) {
        this.ctxt=ctxt;
        appWidgetId=intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                AppWidgetManager.INVALID_APPWIDGET_ID);
    }



    @Override
    public void onCreate() {
        // NO-OP
    }

    @Override
    public void onDestroy() {
        // NO-OP
    }

    @Override
    public int getCount() {
        return(nome_app_HORA.size());
    }

    @Override
    public RemoteViews getViewAt(final int position) {
        final RemoteViews row=new RemoteViews(ctxt.getPackageName(),
                R.layout.list_item);


//FILL LIST
       
        //IMAGE OF THE PACKAGE
        try {
            ApplicationInfo app = ctxt.getPackageManager().getApplicationInfo(pacote_app2.get(position), 0);
            Drawable icon = ctxt.getPackageManager().getApplicationIcon(app);
            Bitmap bmpIcon = ((BitmapDrawable) icon).getBitmap();
            row.setImageViewBitmap(R.id.app_icon, bmpIcon);

        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
       
        //NAME OF THE PACKAGE
        row.setTextViewText(android.R.id.text1, nome_app_HORA.get(position));


//SEND WORD TO MAIN
        Intent i=new Intent();
        Bundle extras=new Bundle();

        extras.putString(WidgetProvider.EXTRA_WORD, nome_app_HORA.get(position));
        i.putExtras(extras);
        row.setOnClickFillInIntent(android.R.id.text1, i);
//--------------
        return(row);
    }

    @Override
    public RemoteViews getLoadingView() {
        return(null);
    }

    @Override
    public int getViewTypeCount() {
        return(1);
    }

    @Override
    public long getItemId(int position) {
        return(position);
    }

    @Override
    public boolean hasStableIds() {
        return(true);
    }

    @Override
    public void onDataSetChanged() {}

}

How can i make this update every 5 minutes? Like fill the list every 5 minutes.
 
Last edited:
Upvote 0

BEST TECH IN 2023

We've been tracking upcoming products and ranking the best tech since 2007. Thanks for trusting our opinion: we get rewarded through affiliate links that earn us a commission and we invite you to learn more about us.

Smartphones