Make Custom Android Launcher
There
are thousands of Android Launcher available in Play Store. Each and
every Android mobile user loves to customize their mobile with different
Android Launcher. If you want to develop your own launcher, this
post helps you to fulfill your wish. In this post, you will find a demo
launcher with layout and code which include many features like Drag & Drop, rearrange the installed application, change the background wallpaper etc.
Here is an example of demo launcher which display all the installed applications in 3*3 Grid View format compatible to all devices.
First of all we need to find all the installed applications from device so we should implement a subclass of AsyncTaskLoader that
loads the currently installed applications from the package manager. If
you want to display all the installed applications in List View you can use official Android Developer reference.
To get the complete Eclipse project, Click Here.
Before going to implement a subclass of AsyncTaskLoader, We must create a class named "AppEntry" that holds each data of an installed application.
Before going to implement a subclass of AsyncTaskLoader, We must create a class named "AppEntry" that holds each data of an installed application.
//***AppEntry.class***
public class AppEntry {
private final AppLoader mLoader;
private final ApplicationInfo mInfo;
private final File mApkFile;
private String mLabel;
private Drawable mIcon;
private boolean mMounted;
public AppEntry(AppLoader appLoader, ApplicationInfo info) {
mLoader=appLoader;
mInfo = info;
mApkFile = new File(info.sourceDir);
}
void loadLabel(Context context) {
if (mLabel == null || !mMounted) {
if (!mApkFile.exists()) {
mMounted = false;
mLabel = mInfo.packageName;
} else {
mMounted = true;
CharSequence label = mInfo.loadLabel(context.getPackageManager());
mLabel = label != null ? label.toString() : mInfo.packageName;
}
}
}
public ApplicationInfo getApplicationInfo() {
return mInfo;
}
public String getLabel() {
return mLabel;
}
public Drawable getIcon() {
if (mIcon == null) {
if (mApkFile.exists()) {
mIcon = mInfo.loadIcon(mLoader.mPm);
return mIcon;
} else {
mMounted = false;
}
} else if (!mMounted) {
if (mApkFile.exists()) {
mMounted = true;
mIcon = mInfo.loadIcon(mLoader.mPm);
return mIcon;
}
} else {
return mIcon;
}
return mLoader.getContext().getResources().getDrawable(
android.R.drawable.sym_def_app_icon);
}
@Override
public String toString() {
return mLabel;
}
}
Now we need a class that helps to update the loader whenever user delete or install new app so make a subclass of BroadcastReceiver which filter the intent by ACTION_PACKAGE_ADDED, _REMOVED and _CHANGED. If there's any application installed in external storage, then we need to register an event for that application using Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE or _UNAVAILABLE.
//***PackageIntentReceiver.class***
public class PackageIntentReceiver extends BroadcastReceiver {
final AppLoader mLoader;
public PackageIntentReceiver(AppLoader loader) {
mLoader = loader;
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
mLoader.getContext().registerReceiver(this, filter);
}
@Override
public void onReceive(Context context, Intent intent) {
mLoader.onContentChanged();
}
}
Here is a custom loader class which is subclass of AsyncTaskLoader<> class that loads all installed apps and store application info, label and icon of a specific app in AppEntry class.
//***AppLoader.class***
public class AppLoader extends AsyncTaskLoader<List<AppEntry>> {
final InterestingConfigChanges mLastConfig = new InterestingConfigChanges();
final PackageManager mPm;
List<AppEntry> mApps;
PackageIntentReceiver mPackageObserver;
public AppLoader(Context context) {
super(context);
mPm = getContext().getPackageManager();
}
@Override
public List<AppEntry> loadInBackground() {
List<ApplicationInfo> apps = mPm.getInstalledApplications(PackageManager.GET_GIDS);
if (apps == null) {
apps = new ArrayList<ApplicationInfo>();
}
final Context context = getContext();
List<AppEntry> entries = new ArrayList<AppEntry>();
for (ApplicationInfo app : apps) {
if(mPm.getLaunchIntentForPackage(app.packageName) != null) {
// get all apps with launcher intent
if((app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 1) {
//get all updated system apps
} else if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 1) {
// system apps
} else {
//get all user installed apps
}
AppEntry entry = new AppEntry(this, app);
entry.loadLabel(context);
entries.add(entry);
}
}
Collections.sort(entries, ALPHA_COMPARATOR);
return entries;
}
public static final Comparator<AppEntry> ALPHA_COMPARATOR = new Comparator<AppEntry>() {
private final Collator sCollator = Collator.getInstance();
@Override
public int compare(AppEntry object1, AppEntry object2) {
return sCollator.compare(object1.getLabel(), object2.getLabel());
}
};
@Override
public void deliverResult(List<AppEntry> apps) {
if (isReset()) {
if (apps != null) {
onReleaseResources(apps);
}
}
List<AppEntry> oldApps = mApps;
mApps = apps;
if (isStarted()) {
super.deliverResult(apps);
}
if (oldApps != null) {
onReleaseResources(oldApps);
}
}
@Override
protected void onStartLoading() {
if (mApps != null) {
deliverResult(mApps);
}
if (mPackageObserver == null) {
mPackageObserver = new PackageIntentReceiver(this);
}
boolean configChange = mLastConfig.applyNewConfig(getContext().getResources());
if (takeContentChanged() || mApps == null || configChange) {
forceLoad();
}
}
@Override protected void onStopLoading() {
cancelLoad();
}
@Override public void onCanceled(List<AppEntry> apps) {
super.onCanceled(apps);
onReleaseResources(apps);
}
@Override protected void onReset() {
super.onReset();
onStopLoading();
if (mApps != null) {
onReleaseResources(mApps);
mApps = null;
}
if (mPackageObserver != null) {
getContext().unregisterReceiver(mPackageObserver);
mPackageObserver = null;
}
}
protected void onReleaseResources(List<AppEntry> apps) {
}
}
Now it's time to make a custom pagerAdapter which add pages to ViewPager. ViewPager class is available on android.support.v4.view.ViewPager package.
//***MyPagerAdapter.class***
public class MyPagerAdapter extends FragmentStatePagerAdapter {
private List<GridFragment> gridFragments;
public MyPagerAdapter(FragmentManager fm, List<GridFragment> gridFragments) {
super(fm);
this.gridFragments = gridFragments;
}
@Override
public Fragment getItem(int arg0) {
return this.gridFragments.get(arg0);
}
@Override
public int getCount() {
return this.gridFragments.size();
}
}
Let's take a look at the Main Activity of our launcher. The main activity class named EaseActivity should be a subclass of FragmentActivity class and should implements LoaderManager.LoaderCallbacks<List<AppEntry>>. This class gets all apps from Loader and make a GridPage named GridFragment with 9 apps per page. At last, all these GridFragments are added to the ViewPager.
//***EaseActivity.class***
public class EaseActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks<List<AppEntry>> {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ease);
getSupportLoaderManager().initLoader(0, null, this);
}
@Override
public Loader<List<AppEntry>> onCreateLoader(
int arg0, Bundle arg1) {
return new AppLoader(this);
}
private ViewPager pager;
private MyPagerAdapter pagerAdapter;
@Override
public void onLoadFinished(Loader<List<AppEntry>> loader,
List<AppEntry> appEntries) {
Iterator<AppEntry> iterator= appEntries.iterator();
List<GridFragment> gridFragments= new ArrayList<GridFragment>();
pager =(ViewPager)findViewById(R.id.pager);
int i=0;
AppEntry entry;
while (iterator.hasNext()) {
ArrayList<GridItems> gridItems=new ArrayList<GridItems>();
entry = iterator.next();
GridItems item=new GridItems(0, entry.getLabel(), entry.getIcon(), entry.getApplicationInfo());
gridItems.add(item);
i=i+1;
if (iterator.hasNext()) {
entry = iterator.next();
GridItems item1=new GridItems(1, entry.getLabel(), entry.getIcon(), entry.getApplicationInfo());
gridItems.add(item1);
i=i+1;
}
if (iterator.hasNext()) {
entry = iterator.next();
GridItems item2=new GridItems(2, entry.getLabel(), entry.getIcon(), entry.getApplicationInfo());
gridItems.add(item2);
i=i+1;
}
if (iterator.hasNext()) {
entry = iterator.next();
GridItems item3=new GridItems(3, entry.getLabel(), entry.getIcon(), entry.getApplicationInfo());
gridItems.add(item3);
i=i+1;
}
if (iterator.hasNext()) {
entry = iterator.next();
GridItems item4=new GridItems(4, entry.getLabel(), entry.getIcon(), entry.getApplicationInfo());
gridItems.add(item4);
i=i+1;
}
if (iterator.hasNext()) {
entry = iterator.next();
GridItems item5=new GridItems(5, entry.getLabel(), entry.getIcon(), entry.getApplicationInfo());
gridItems.add(item5);
i=i+1;
}
if (iterator.hasNext()) {
entry = iterator.next();
GridItems item6=new GridItems(6, entry.getLabel(), entry.getIcon(), entry.getApplicationInfo());
gridItems.add(item6);
i=i+1;
}
if (iterator.hasNext()) {
entry = iterator.next();
GridItems item7=new GridItems(7, entry.getLabel(), entry.getIcon(), entry.getApplicationInfo());
gridItems.add(item7);
i=i+1;
}
if (iterator.hasNext()) {
entry = iterator.next();
GridItems item8=new GridItems(8, entry.getLabel(), entry.getIcon(), entry.getApplicationInfo());
gridItems.add(item8);
i=i+1;
}
GridItems[] gp = {};
GridItems[] gridPage = gridItems.toArray(gp);
gridFragments.add(new GridFragment(gridPage, EaseActivity.this));
}
pagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), gridFragments);
pager.setAdapter(pagerAdapter);
}
@Override
public void onLoaderReset(Loader<List<AppEntry>> arg0) {
}
}
Here is the GridFragment class. This class works as a page and apps are added to this page using GridAdapter. The drag and drop feature defined in this class.
//***GridFragment.class***
public class GridFragment extends Fragment {
private GridView mGridView;
private GridView dockView;
private GridAdapter mGridAdapter;
GridItems[] gridItems = {};
private Activity mainActivity;
public GridFragment(GridItems[] gridItems, Activity mainActivity) {
this.gridItems = gridItems;
this.mainActivity = mainActivity;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view;
view = inflater.inflate(R.layout.grid_page, container, false);
mGridView = (GridView) view.findViewById(R.id.gridView);
dockView = (GridView) view.findViewById(R.id.dock);
float scalefactor = getResources().getDisplayMetrics().density * 100;
int number = mainActivity.getWindowManager().getDefaultDisplay().getWidth();
int columns = (int) ((float) number / (float) scalefactor);
mGridView.setNumColumns(3);
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (mainActivity != null) {
mGridAdapter = new GridAdapter(mainActivity, gridItems);
if (mGridView != null) {
mGridView.setAdapter(mGridAdapter);
}
mGridView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView parent, View view,
int position, long id) {
onGridItemClick((GridView) parent, view, position, id);
}
});
mGridView.setOnItemLongClickListener(new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view,
int position, long id) {
dragANDdrop(parent,view,position,id);
return false;
}
});
}
}
protected void dragANDdrop(AdapterView<?> parent, View view,
int position, long id) {
int count = parent.getChildCount();
for (int i = 0; i < count; i++) {
View curr = parent.getChildAt(i);
curr.setOnDragListener(new View.OnDragListener() {
@Override
public boolean onDrag(View v, DragEvent event) {
boolean result = true;
int action = event.getAction();
switch (action)
{
case DragEvent.ACTION_DRAG_STARTED:
break;
case DragEvent.ACTION_DRAG_LOCATION:
break;
case DragEvent.ACTION_DRAG_ENTERED:
break;
case DragEvent.ACTION_DRAG_EXITED:
break;
case DragEvent.ACTION_DROP:
if(event.getLocalState()==v){result=false;}
else{
View droped=(View)event.getLocalState();
GridItems dropItem = ((ViewHolder)droped.getTag()).item;
GridView parent= (GridView)droped.getParent();
GridAdapter gridAdapter = (GridAdapter)parent.getAdapter();
GridItems[] gridItemss = gridAdapter.getItems();
View target=v;
GridItems targetItem = ((ViewHolder)target.getTag()).item;
List<GridItems> list = new ArrayList<GridItems>(Arrays.asList(gridItemss));
int index = list.indexOf(targetItem);
list.remove(dropItem);
list.add(index, dropItem);
gridItemss = list.toArray(gridItemss);
gridAdapter.notifyDataSetChanged();
}
break;
case DragEvent.ACTION_DRAG_ENDED:
break;
default:
result = false;
break;
}
return result;
}
});
}
int relativePosition = position - parent.getFirstVisiblePosition();
View target=(View)parent.getChildAt(relativePosition);
ViewHolder holder= ((ViewHolder)target.getTag());
GridItems currItem=holder.item;
String path=currItem.title;
ClipData clipData=ClipData.newPlainText("DragData", path);
target.startDrag(clipData, new View.DragShadowBuilder(target), target, 0);
}
public void onGridItemClick(GridView g, View v, int position, long id) {
ApplicationInfo info = gridItems[position].info;
Intent intent= getActivity().getPackageManager().getLaunchIntentForPackage(info.packageName);
startActivity(intent);
}
}
A GridAdapter class that fill apps data in GridFragment class.
//***GridAdapter.class***
public class GridAdapter extends BaseAdapter {
Context context;
public class ViewHolder {
public ImageView imageView;
public TextView textTitle;
public GridItems item;
}
private GridItems[] items;
private LayoutInflater mInflater;
public GridAdapter(Context context, GridItems[] locations) {
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.context = context;
items = locations;
}
public GridItems[] getItems() {
return items;
}
public void setItems(GridItems[] items) {
this.items = items;
}
@Override
public int getCount() {
if (items != null) {
return items.length;
}
return 0;
}
@Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
@Override
public Object getItem(int position) {
if (items != null && position >= 0 && position < getCount()) {
return items[position];
}
return null;
}
@Override
public long getItemId(int position) {
if (items != null && position >= 0 && position < getCount()) {
return items[position].id;
}
return 0;
}
public void setItemsList(GridItems[] locations) {
this.items = locations;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
ViewHolder viewHolder;
if (view == null) {
view = mInflater.inflate(R.layout.show_app, parent, false);
viewHolder = new ViewHolder();
viewHolder.imageView = (ImageView) view.findViewById(R.id.grid_item_image);
viewHolder.textTitle = (TextView) view.findViewById(R.id.grid_item_label);
view.setTag(viewHolder);
}
else
{
viewHolder = (ViewHolder) view.getTag();
}
GridItems gridItems = items[position];
viewHolder.item = items[position];
viewHolder.imageView.setImageDrawable(gridItems.drawable);
viewHolder.textTitle.setText(gridItems.title);
return view;
}
}

Comments
Post a Comment