In this tutorial, I will make a completed app which will listing all installed apps in Android and provide some extra features: search, directly running,...to make a "shortcut" when launching any app in our own device.
Project source code now available on Github, you can check it. First, please see this DEMO VIDEO, app run with Genymotion emulator:
Listing all Apps
As note above, we will a PackageManager instance to get all installed app. In programmatically code for activity, this process declaration only 2 lines:
PackageManager packageManager = getPackageManager(); List<Applicationinfo> list = packageManager.getInstalledApplications(PackageManager.GET_META_DATA)For app running well, we should do this process in a background thread by an AsyncTask. So, with getInstalledApplications() method was called in doInbackground(), an ApplicationInfo list will be return in onPostExcute(). Full source code for this AsyncTask:
package devexchanges.info.appslist;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import java.util.ArrayList;
import java.util.List;
public class GetAllAppsTask extends AsyncTask<Void, Void, List<ApplicationInfo>> {
private MainActivity activity;
private List<Applicationinfo> apps;
private PackageManager packageManager;
public GetAllAppsTask(MainActivity activity, List<Applicationinfo> apps, PackageManager pm) {
this.activity = activity;
this.apps = apps;
this.packageManager = pm;
}
@Override
protected List<Applicationinfo> doInBackground(Void... params) {
apps = checkForLaunchIntent(packageManager.getInstalledApplications(PackageManager.GET_META_DATA));
return apps;
}
private List<Applicationinfo> checkForLaunchIntent(List<Applicationinfo> list) {
ArrayList<Applicationinfo> applist = new ArrayList<>();
for (ApplicationInfo applicationInfo : list) {
try {
if (packageManager.getLaunchIntentForPackage(applicationInfo.packageName) != null) {
applist.add(applicationInfo);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
return applist;
}
@Override
protected void onPostExecute(List<Applicationinfo> list) {
super.onPostExecute(list);
activity.callBackDataFromAsynctask(list);
}
}
In onPostExcute() method, I've called back data to main activity and update views. So, this method in activity code is simple like this: public void callBackDataFromAsynctask(List<Applicationinfo> list) {
applicationInfos.clear();
for (int i = 0; i < list.size(); i++) {
applicationInfos.add(list.get(i));
}
headerText.setText("All Apps (" + applicationInfos.size() + ")");
adapter.notifyDataSetChanged();
progressDialog.dismiss(); //dismiss progressing dialog
}
In order to our app always update, invoke AsynTask in onStart() method: @Override
protected void onStart() {
super.onStart();
//invoke asynctask
new GetAllAppsTask(this, applicationInfos, packageManager).execute();
}
Create SearchView to filter List
First, make a Toolbar layout and include I was included it in activity_main.xml above: Create a menu in our activity (in res/menu folder):
Back to activity code, create menu in onCreateOptionsMenu() and provide OnQueryTextListener for SearchView, when we typing on it, app will filter ListView through call:
//filter adapter and update ListView adapter.getFilter().filter(s);Creating menu search methods:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
// Inflate menu to add items to action bar if it is present.
inflater.inflate(R.menu.menu_main, menu);
// Associate searchable configuration with the SearchView
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
searchView.setOnQueryTextListener(onQueryTextListener()); // text changed listener
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
return true;
}
private SearchView.OnQueryTextListener onQueryTextListener() {
return new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
return false;
}
@Override
public boolean onQueryTextChange(String s) {
//filter adapter and update ListView
adapter.getFilter().filter(s);
return false;
}
};
}
Customizing a ListView Adapter
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
// If holder not exist then locate all view from UI file.
if (convertView == null) {
// inflate UI from XML file
convertView = inflater.inflate(R.layout.item_listview, parent, false);
// get all UI view
holder = new ViewHolder(convertView);
// set tag for holder
convertView.setTag(holder);
} else {
// if holder created, get tag from view
holder = (ViewHolder) convertView.getTag();
}
//setting data to views
holder.appName.setText(getItem(position).loadLabel(packageManager)); //get app name
holder.appPackage.setText(getItem(position).packageName); //get app package
holder.icon.setImageDrawable(getItem(position).loadIcon(packageManager)); //get app icon
//set on click event for each item view
convertView.setOnClickListener(onClickListener(position));
return convertView;
}
private class ViewHolder {
private ImageView icon;
private TextView appName;
private TextView appPackage;
public ViewHolder(View v) {
icon = (ImageView) v.findViewById(R.id.icon);
appName = (TextView) v.findViewById(R.id.name);
appPackage = (TextView) v.findViewById(R.id.app_package);
}
}
When clicking at each item, getting this item (app) packagename through getLaunchIntentForPackage() and lauched it by Intent: private View.OnClickListener onClickListener(final int position) {
return new View.OnClickListener() {
@Override
public void onClick(View v) {
ApplicationInfo app = appsList.get(position);
try {
Intent intent = packageManager.getLaunchIntentForPackage(app.packageName);
activity.startActivity(intent);
if (null != intent) {
activity.startActivity(intent);
}
} catch (ActivityNotFoundException e) {
e.printStackTrace();
}
}
};
}
Create customize Filter in our adapter to filtering data (ApplicationInfos List). We will override performFiltering() and publishResult() methods:private class AppsFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint != null && constraint.length() > 0) {
ArrayList<Applicationinfo> filterList = new ArrayList<Applicationinfo>();
for (int i = 0; i < originalList.size(); i++) {
if ((originalList.get(i).loadLabel(packageManager).toString().toUpperCase())
.contains(constraint.toString().toUpperCase())) {
ApplicationInfo applicationInfo = originalList.get(i);
filterList.add(applicationInfo);
}
}
results.count = filterList.size();
results.values = filterList;
} else {
results.count = originalList.size();
results.values = originalList;
}
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
appsList = (ArrayList<Applicationinfo>) results.values;
notifyDataSetChanged();
if (appsList.size() == originalList.size()) {
activity.updateUILayout("All apps (" + appsList.size() + ")");
} else {
activity.updateUILayout("Filtered apps (" + appsList.size() + ")");
}
}
}
Final code
Code for main activity:
package devexchanges.info.appslist;
import android.app.ProgressDialog;
import android.app.SearchManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ListView listView;
private TextView headerText;
private Toolbar toolbar;
private PackageManager packageManager;
private ArrayAdapter<Applicationinfo> adapter;
private ArrayList<Applicationinfo> applicationInfos;
private ProgressDialog progressDialog;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
packageManager = getPackageManager();
applicationInfos = new ArrayList<>();
//find View by id
listView = (ListView) findViewById(R.id.list_view);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//show progress dialog
progressDialog = ProgressDialog.show(this, "Loading All Apps", "Loading application info...");
//set list view adapter
LayoutInflater inflater = getLayoutInflater();
View header = inflater.inflate(R.layout.layout_lv_header, listView, false);
headerText = (TextView) header.findViewById(R.id.text_header);
listView.addHeaderView(header, null, false);
//initializing and set adapter for listview
adapter = new ApplicationAdapter(this, R.layout.item_listview, applicationInfos);
listView.setAdapter(adapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
// Inflate menu to add items to action bar if it is present.
inflater.inflate(R.menu.menu_main, menu);
// Associate searchable configuration with the SearchView
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
searchView.setOnQueryTextListener(onQueryTextListener()); // text changed listener
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
return true;
}
private SearchView.OnQueryTextListener onQueryTextListener() {
return new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
return false;
}
@Override
public boolean onQueryTextChange(String s) {
//filter adapter and update ListView
adapter.getFilter().filter(s);
return false;
}
};
}
@Override
protected void onStart() {
super.onStart();
//invoke asynctask
new GetAllAppsTask(this, applicationInfos, packageManager).execute();
}
public void callBackDataFromAsynctask(List<Applicationinfo> list) {
applicationInfos.clear();
for (int i = 0; i < list.size(); i++) {
applicationInfos.add(list.get(i));
}
headerText.setText("All Apps (" + applicationInfos.size() + ")");
adapter.notifyDataSetChanged();
progressDialog.dismiss();
}
public void updateUILayout(String content) {
headerText.setText(content);
}
}
ListView adapter class, defining a customize Filter:
package devexchanges.info.appslist;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class ApplicationAdapter extends ArrayAdapter<Applicationinfo> {
private List<Applicationinfo> appsList;
private List<Applicationinfo> originalList;
private MainActivity activity;
private PackageManager packageManager;
private AppsFilter filter;
public ApplicationAdapter(MainActivity activity, int textViewResourceId, List<Applicationinfo> appsList) {
super(activity, textViewResourceId, appsList);
this.activity = activity;
this.appsList = appsList;
this.originalList = appsList;
packageManager = activity.getPackageManager();
}
@Override
public int getCount() {
return appsList.size();
}
@Override
public ApplicationInfo getItem(int position) {
return appsList.get(position);
}
@Override
public long getItemId(int position) {
return appsList.indexOf(getItem(position));
}
@Override
public Filter getFilter() {
if (filter == null) {
filter = new AppsFilter();
}
return filter;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
// If holder not exist then locate all view from UI file.
if (convertView == null) {
// inflate UI from XML file
convertView = inflater.inflate(R.layout.item_listview, parent, false);
// get all UI view
holder = new ViewHolder(convertView);
// set tag for holder
convertView.setTag(holder);
} else {
// if holder created, get tag from view
holder = (ViewHolder) convertView.getTag();
}
//setting data to views
holder.appName.setText(getItem(position).loadLabel(packageManager)); //get app name
holder.appPackage.setText(getItem(position).packageName); //get app package
holder.icon.setImageDrawable(getItem(position).loadIcon(packageManager)); //get app icon
//set on click event for each item view
convertView.setOnClickListener(onClickListener(position));
return convertView;
}
private View.OnClickListener onClickListener(final int position) {
return new View.OnClickListener() {
@Override
public void onClick(View v) {
ApplicationInfo app = appsList.get(position);
try {
Intent intent = packageManager.getLaunchIntentForPackage(app.packageName);
activity.startActivity(intent);
if (null != intent) {
activity.startActivity(intent);
}
} catch (ActivityNotFoundException e) {
e.printStackTrace();
}
}
};
}
private class ViewHolder {
private ImageView icon;
private TextView appName;
private TextView appPackage;
public ViewHolder(View v) {
icon = (ImageView) v.findViewById(R.id.icon);
appName = (TextView) v.findViewById(R.id.name);
appPackage = (TextView) v.findViewById(R.id.app_package);
}
}
private class AppsFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint != null && constraint.length() > 0) {
ArrayList<Applicationinfo> filterList = new ArrayList<Applicationinfo>();
for (int i = 0; i < originalList.size(); i++) {
if ((originalList.get(i).loadLabel(packageManager).toString().toUpperCase())
.contains(constraint.toString().toUpperCase())) {
ApplicationInfo applicationInfo = originalList.get(i);
filterList.add(applicationInfo);
}
}
results.count = filterList.size();
results.values = filterList;
} else {
results.count = originalList.size();
results.values = originalList;
}
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
appsList = (ArrayList<Applicationinfo>) results.values;
notifyDataSetChanged();
if (appsList.size() == originalList.size()) {
activity.updateUILayout("All apps (" + appsList.size() + ")");
} else {
activity.updateUILayout("Filtered apps (" + appsList.size() + ")");
}
}
}
}
Each ListView item layout:
Strings resource: Colors resource: Styling our app:
Conclusion
You can directly download app apk HERE!
Update: version 2.0: add feature: swipe to Uninstall an app, fix layout for tablet. Check this direct link for new apk file.

