user2909006
user2909006

Reputation: 253

Failed Binder Transaction is Ruining Entire Widget

In my widget, I am constantly getting this error:

11-02 09:35:10.613: D/D&D(1557): onCreate called
11-02 09:35:10.933: E/JavaBinder(1557): !!! FAILED BINDER TRANSACTION !!!
11-02 09:35:10.933: D/AppInfoAdapter(1557): top

No matter what I seem to do (I've tried cutting down bitmap sizes, making bitmaps static, commenting out parts of my coding to see where the error was (which didn't help at all by the way)), I always get this error. What this error is causing is that it makes my listView of the users installed applications not show up at all (it's just white space) in a sliding drawer. All my links and other classes work just fine. (But my listView is the center piece and major function of my entire widget.)

I'm at a loss now so I am just going to post the three suspected classes that I've concluded this is steming from (because all the other classes work fine).

Please note that some code is commented out (such as coding for drag and drop functionality because my real device doesn't support honeycomb. I will implement that code when my listView starts working again however)

AppInfoAdapter.java:

package com.example.awesomefilebuilderwidget;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.TextView;

public class AppInfoAdapter extends BaseAdapter implements Filterable {
private Context mContext;
private List<PackageInfo> mListAppInfo;
private PackageManager mPackManager;
private List<PackageInfo> originalListAppInfo;
private Filter filter;

public AppInfoAdapter(Context c, List<PackageInfo> listApp,
        PackageManager pm) {
    mContext = c;
    this.originalListAppInfo = this.mListAppInfo = listApp;
    mPackManager = pm;
    Log.d("AppInfoAdapter", "top");
}

@Override
public int getCount() {
    Log.d("AppInfoAdapter", "getCount()");
    return mListAppInfo.size();
}

@Override
public Object getItem(int position) {
    Log.d("AppInfoAdapter", "getItem");
    return mListAppInfo.get(position);
}

@Override
public long getItemId(int position) {
    Log.d("AppInfoAdapter", "getItemId");
    return position;
}

public static Bitmap scaleDownBitmap(Bitmap default_b, int newHeight, Context c) {

    final float densityMultiplier = c.getResources().getDisplayMetrics().density;

    int h= (int) (100*densityMultiplier);
    int w= (int) (h * default_b.getWidth()/((double) default_b.getHeight()));

    default_b=Bitmap.createScaledBitmap(default_b, w, h, true);
    // TO SOLVE LOOK AT HERE:https://stackoverflow.com/questions/15517176/passing-bitmap-to-other-activity-getting-message-on-logcat-failed-binder-transac
    return default_b;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    // get the selected entry
    final PackageInfo entry = (PackageInfo) mListAppInfo.get(position);

    // reference to convertView
    View v = convertView;

    // inflate new layout if null
    if (v == null) {
        LayoutInflater inflater = LayoutInflater.from(mContext);
        v = inflater.inflate(R.layout.layout_appinfo, null);
        Log.d("AppInfoAdapter", "New layout inflated");
    }

    // load controls from layout resources
    ImageView ivAppIcon = (ImageView) v.findViewById(R.id.ivIcon);
    TextView tvAppName = (TextView) v.findViewById(R.id.tvName);
    TextView tvPkgName = (TextView) v.findViewById(R.id.tvPack);
    final CheckBox addCheckbox = (CheckBox) v
            .findViewById(R.id.addCheckbox);
    Log.d("AppInfoAdapter", "Controls from layout Resources Loaded");

    // set data to display
    ivAppIcon.setImageDrawable(entry.applicationInfo.loadIcon(mPackManager));
    tvAppName.setText(entry.applicationInfo.loadLabel(mPackManager));
    tvPkgName.setText(entry.packageName);
    Log.d("AppInfoAdapter", "Data Set To Display");
    addCheckbox
            .setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {
                    if (addCheckbox.isChecked()) {
                        System.out.println("Checked");
                        PackageManager pm = mContext.getPackageManager();
                        Drawable icon = null;
                        try {
                            icon = pm
                                    .getApplicationIcon(entry.packageName);
                        } catch (NameNotFoundException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        Drawable default_icon = pm.getDefaultActivityIcon();
                        if (icon instanceof BitmapDrawable
                                && default_icon instanceof BitmapDrawable) {
                            BitmapDrawable icon_bd = (BitmapDrawable) icon;
                            Bitmap icon_b = icon_bd.getBitmap();
                            BitmapDrawable default_bd = (BitmapDrawable) pm
                                    .getDefaultActivityIcon();
                            Bitmap default_b = default_bd.getBitmap();
                            if (icon_b == default_b) {
                                // It's the default icon
                                scaleDownBitmap(default_b, 100, v.getContext());
                                Log.d("AppInfoAdapter", "Scale Bitmap Chosen");

                                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                                default_b.compress(Bitmap.CompressFormat.PNG, 100, stream);
                                byte[] byteArray = stream.toByteArray();
                                Log.d("AppInfoAdapter", "Scale Bitmap to Array");

                                Intent intent = new Intent(v.getContext(), GridView.class);
                                intent.putExtra("picture", byteArray);
                                v.getContext().startActivity(intent);
                                Log.d("AppInfoAdapter", "Intent started to send Bitmap");
                            }
                        }
                    } else {
                        System.out.println("Un-Checked");
                    }

                }
            });

    // return view
    return v;
}

@Override
public Filter getFilter() {
    if (filter == null) {
        filter = new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults results = new FilterResults();
                List<PackageInfo> myFilteredAppList = new ArrayList<PackageInfo>();
                constraint = constraint.toString().toLowerCase();

                if (constraint.length() == 0) {
                    myFilteredAppList.addAll(originalListAppInfo);

                }

                for (PackageInfo appInfo : originalListAppInfo) {
                    String somefield = appInfo.packageName;
                    String name = appInfo.packageName;
                    if (somefield.toLowerCase().contains(
                            constraint.toString().toLowerCase().toString())
                            || (name != null && name.toLowerCase()
                                    .contains(
                                            constraint.toString()
                                                    .toLowerCase()
                                                    .toString()))) {
                        myFilteredAppList.add(appInfo);
                    }
                }
                results.count = myFilteredAppList.size();
                results.values = myFilteredAppList;
                return results;
            }

            @Override
            protected void publishResults(CharSequence constraint,
                    FilterResults results) {

                if (results.values != null) {
                    mListAppInfo = (List<PackageInfo>) results.values;
                    notifyDataSetChanged();
                }
            }
        };
    }
    return filter;
}

}

Drag_and_Drop_App (snippet):

public class Drag_and_Drop_App extends Activity {
private static final int SET_BACKGROUND = 10;

private ListView mListAppInfo;
// Search EditText
EditText inputSearch;
public AppInfoAdapter adapter;
final SwipeDetector swipeDetector = new SwipeDetector();

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // set layout for the main screen
    setContentView(R.layout.drag_and_drop_app);

    // import buttons
    Button btnLinkToPersonalize = (Button) findViewById(R.id.btnLinkToPersonalize);
    Log.d("D&D", "onCreate called");

    // create new adapter
    adapter = new AppInfoAdapter(this, (List<PackageInfo>) Utilities.getInstalledApplications(this), getPackageManager());
    // load list application
   mListAppInfo = (ListView)findViewById(R.id.lvApps);
    // set adapter to list view
    mListAppInfo.setAdapter(adapter);
    // search bar
    inputSearch = (EditText) findViewById(R.id.inputSearch);

    inputSearch.addTextChangedListener(new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
            // When user changed the Text
            // Drag_and_Drop_App.this.adapter.getFilter().filter(cs);  
             if (Drag_and_Drop_App.this.adapter == null){
                 // some print statement saying it is null
                 Log.d ("msg_error", "adapter_is_null");
             }
                Drag_and_Drop_App.this.adapter.getFilter().filter(cs);

            }

        @Override
        public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
                int arg3) {
            // TODO Auto-generated method stub

        }

        @Override
        public void afterTextChanged(Editable arg0) {
            // TODO Auto-generated method stub                          
        }
        });


    // implement event when an item on list view is selected
    mListAppInfo.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
            // get the list adapter
            AppInfoAdapter appInfoAdapter = (AppInfoAdapter)parent.getAdapter();
            // get selected item on the list
            PackageInfo appInfo = (PackageInfo)appInfoAdapter.getItem(pos);
            // launch the selected application
            Utilities.launchApp(parent.getContext(), getPackageManager(), appInfo.packageName);
        }

    });

    // implement event when an item on list view is selected via long-click 
    mListAppInfo.setOnItemLongClickListener(new OnItemLongClickListener(){

        @Override
        public boolean onItemLongClick(AdapterView<?> parent, View view,int pos, long id) {
            if (swipeDetector.swipeDetected()){
                // do the onSwipe action 
            } else {
                // do the onItemLongClick action
                // get the list adapter
                AppInfoAdapter appInfoAdapter = (AppInfoAdapter)parent.getAdapter();
                // get selected item on the list
                PackageInfo appInfo = (PackageInfo)appInfoAdapter.getItem(pos);
                // launch the selected application
                Utilities.launchApp(parent.getContext(), getPackageManager(), appInfo.packageName);
                Log.d("D&D", "App launched");

            }
            return true;
        }
    });

    // implement slide event to open up plus button
    mListAppInfo.setOnTouchListener(swipeDetector);
    mListAppInfo.setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
                if (swipeDetector.swipeDetected()){
                    // do the onSwipe action 
                    // TEST TO MAKE SURE SWIPE WORKS
                    AppInfoAdapter appInfoAdapter = (AppInfoAdapter)parent.getAdapter();
                    // get selected item on the list
                    PackageInfo appInfo = (PackageInfo)appInfoAdapter.getItem(pos);
                    // launch the selected application
                    Utilities.launchApp(parent.getContext(), getPackageManager(), appInfo.packageName);
                } else {
                    // do the onItemClick action
                    // get the list adapter
                    AppInfoAdapter appInfoAdapter = (AppInfoAdapter)parent.getAdapter();
                    // get selected item on the list
                    PackageInfo appInfo = (PackageInfo)appInfoAdapter.getItem(pos);
                    // launch the selected application
                    Utilities.launchApp(parent.getContext(), getPackageManager(), appInfo.packageName);
                }
            }
    });

And finally GridView.java:

package com.example.awesomefilebuilderwidget;

import java.util.ArrayList;

import android.app.Activity;
import android.content.ClipData;
import android.content.ClipDescription;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.DragEvent;
import android.view.View;
import android.view.View.OnDragListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;

public class GridView extends Activity { // implements OnItemLongClickListener, OnDragListener{

ArrayList<Integer> drawables = new ArrayList<Integer>();

private BaseAdapter adapter;
private int draggedIndex = -1;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.drag_and_drop_app);
    Log.d("GridView", "onCreate called");
    drawables = new ArrayList<Integer>();
    drawables.add(R.drawable.pattern1);
    drawables.add(R.drawable.pattern2);
    android.widget.GridView gridView = (android.widget.GridView) findViewById(R.id.grid_view);
    // gridView.setOnItemLongClickListener(this);
    gridView.setAdapter(adapter = new BaseAdapter() {

        @Override
        // Get a View that displays the data at the specified position in
        // the data set.
        public View getView(int position, View convertView,
                ViewGroup gridView) {
            // try to reuse the views.
            ImageView view = (ImageView) convertView;
            // if convert view is null then create a new instance else reuse
            // it
            if (view == null) {
                view = new ImageView(GridView.this);
            }
            Bundle extras = getIntent().getExtras();
            byte[] byteArray = extras.getByteArray("picture");

            Bitmap default_b = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);

            view.setImageBitmap(default_b);
            view.setImageResource(drawables.get(position));
            view.setScaleType(ImageView.ScaleType.CENTER_CROP);
            view.setLayoutParams(new android.widget.GridView.LayoutParams(70, 70));
            view.setTag(String.valueOf(position));
            return view;
        }

        @Override
        // Get the row id associated with the specified position in the
        // list.
        public long getItemId(int position) {
            return position;
        }

        @Override
        // Get the data item associated with the specified position in the
        // data set.
        public Object getItem(int position) {
            return drawables.get(position);
        }

        @Override
        // How many items are in the data set represented by this Adapter.
        public int getCount() {
            return drawables.size();
        }
    });
}

/*@Override
public boolean onItemLongClick(AdapterView<?> gridView, View view,
        int position, long row) {
    ClipData.Item item = new ClipData.Item((String) view.getTag());
    ClipData clipData = new ClipData((CharSequence) view.getTag(),
            new String[] { ClipDescription.MIMETYPE_TEXT_PLAIN }, item);
    view.startDrag(clipData, new View.DragShadowBuilder(view), null, 0);
    View trashCan = findViewById(R.id.trash_can);
    trashCan.setVisibility(View.VISIBLE);
    trashCan.setOnDragListener(GridView.this);
    trashCan.setOnDragListener(GridView.this);
    draggedIndex = position;
    return true;
}

@Override
public boolean onDrag(View view, DragEvent dragEvent) {
    switch (dragEvent.getAction()) {
    case DragEvent.ACTION_DRAG_STARTED:
        // Drag has started
        // If called for trash resize the view and return true
        if (view.getId() == R.id.trash_can) {
            view.animate().scaleX(1.0f);
            view.animate().scaleY(1.0f);
            return true;
        } else // else check the mime type and set the view visibility
        if (dragEvent.getClipDescription().hasMimeType(
                ClipDescription.MIMETYPE_TEXT_PLAIN)) {
            view.setVisibility(View.GONE);
            return true;

        } else {
            return false;
        }
    case DragEvent.ACTION_DRAG_ENTERED:
        // Drag has entered view bounds
        // If called for trash can then scale it.
        if (view.getId() == R.id.trash_can) {
            view.animate().scaleX(1.5f);
            view.animate().scaleY(1.5f);
        }
        return true;
    case DragEvent.ACTION_DRAG_EXITED:
        // Drag exited view bounds
        // If called for trash can then reset it.
        if (view.getId() == R.id.trash_can) {
            view.animate().scaleX(1.0f);
            view.animate().scaleY(1.0f);
        }
        view.invalidate();
        return true;
    case DragEvent.ACTION_DRAG_LOCATION:
        // Ignore this event
        return true;
    case DragEvent.ACTION_DROP:
        // Dropped inside view bounds
        // If called for trash can then delete the item and reload the grid
        // view
        if (view.getId() == R.id.trash_can) {
            drawables.remove(draggedIndex);
            draggedIndex = -1;
        }
        adapter.notifyDataSetChanged();
    case DragEvent.ACTION_DRAG_ENDED:
        // Hide the trash can
        new Handler().postDelayed(new Runnable() {

            @Override
            public void run() {
                findViewById(R.id.trash_can).setVisibility(View.GONE);
            }
        }, 1000l);
        if (view.getId() == R.id.trash_can) {
            view.animate().scaleX(1.0f);
            view.animate().scaleY(1.0f);
        } else {
            view.setVisibility(View.VISIBLE);
        }
        // remove drag listeners
        view.setOnDragListener(null);
        return true;

    }
    return false;
}*/



}

Please comment if you notice ANYTHING that doesn't seem right or that is wrong. I have been trying to fix this error for days and have tried the stackoverflow links here, here, here, and others on top of those.

Please help me to fix this error that I keep getting. I'm really at a loss at what to do now...

(Thanks for reading all of this too, I know it was a lot)

Here is my Utilities class:

package com.example.awesomefilebuilderwidget;

import java.util.List;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;


public class Utilities {

/*
 * Get all installed application on mobile and return a list
 * @param   c   Context of application
 * @return  list of installed applications
 */
public static List<PackageInfo> getInstalledApplications(Context c) {
    return c.getPackageManager().getInstalledPackages(PackageManager.GET_ACTIVITIES);
}

Upvotes: 2

Views: 3786

Answers (2)

user2909006
user2909006

Reputation: 253

It turned out that I was recieving too much information from the packageManager when I was getting the list of installed applications i.e.

Utilities.getInstalledApplications(this)

In my Utilities class. So then I thought that instead of getting ALL of the installed applications, that I should just get the users installed applications (excluding the system ones that are pointless for my use anyways). Here is the updated class:

public class Utilities {

/*
 * Get all installed application on mobile and return a list
 * @param   c   Context of application
 * @return  list of installed applications
 */
public static List<ResolveInfo> getInstalledApplications(Context c) {
    Intent intent = new Intent(Intent.ACTION_MAIN);
    intent.addCategory(Intent.CATEGORY_LAUNCHER);
    return c.getPackageManager().queryIntentActivities(intent, PackageManager.GET_ACTIVITIES);
}

Then of course any list with

<PackageInfo> 

had to be changed to

<ResolveInfo> 

but it worked like a charm!

Upvotes: 1

CommonsWare
CommonsWare

Reputation: 1007359

PackageManager methods, like getInstalledPackages(), can result in a binder transaction error, if the sum total of information being returned is greater than 1MB.

One way to mitigate this is to pass in no flags (e.g., skip PackageManager.GET_ACTIVITIES) to reduce the amount of data in the first call. Then, for those packages where you need the additional detail, call getPackageInfo() to get the details for a specific package. While this does involve multiple IPC round-trips, and therefore is slower, it will help prevent you from blowing out the 1MB-per-transaction limit.

Upvotes: 5

Related Questions