152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project/*
252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project *
452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project * you may not use this file except in compliance with the License.
652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project * You may obtain a copy of the License at
752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project *
852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project *
1052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project * See the License for the specific language governing permissions and
1452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project * limitations under the License.
1552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project */
1652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
1752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectpackage com.android.development;
1852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
1952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.app.AlertDialog;
2052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.app.ListActivity;
2152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.content.Context;
2252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.content.pm.IPackageDeleteObserver;
2352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.content.Intent;
2452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.content.IntentFilter;
2552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.content.BroadcastReceiver;
2652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.content.pm.PackageInfo;
27f9b8546aca4f14956081fff8c3a32a59cd3daa87Kenny Rootimport android.content.pm.PackageManager;
2852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.net.Uri;
2952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.os.Bundle;
3052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.os.RemoteException;
3152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.os.Handler;
3252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.view.Menu;
3352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.view.MenuItem;
3452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.view.View;
355bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackbornimport android.widget.ImageView;
3652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.widget.ListView;
3752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.widget.TextView;
3852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
3952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport java.text.Collator;
405bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackbornimport java.util.ArrayList;
4152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport java.util.Collections;
4252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport java.util.Comparator;
4352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport java.util.List;
4452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
455bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackbornpublic class PackageBrowser extends ListActivity {
465bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn    static class MyPackageInfo {
475bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn        PackageInfo info;
485bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn        String label;
495bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn    }
505bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn
5152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    private PackageListAdapter mAdapter;
525bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn    private List<MyPackageInfo> mPackageInfoList = new ArrayList<MyPackageInfo>();
5352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    private Handler mHandler;
545bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn    private BroadcastReceiver mRegisteredReceiver;
555bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn
565bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn    public class PackageListAdapter extends ArrayAdapter<MyPackageInfo> {
575bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn
585bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn        public PackageListAdapter(Context context) {
595bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn            super(context, R.layout.package_list_item);
605bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn            List<PackageInfo> pkgs = context.getPackageManager().getInstalledPackages(0);
615bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn            for (int i=0; i<pkgs.size(); i++) {
625bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn                MyPackageInfo info = new MyPackageInfo();
635bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn                info.info = pkgs.get(i);
645bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn                info.label = info.info.applicationInfo.loadLabel(getPackageManager()).toString();
655bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn                mPackageInfoList.add(info);
665bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn            }
6752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            if (mPackageInfoList != null) {
6852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                Collections.sort(mPackageInfoList, sDisplayNameComparator);
6952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            }
7052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            setSource(mPackageInfoList);
7152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        }
7252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
7352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        @Override
745bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn        public void bindView(View view, MyPackageInfo info) {
755bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn            ImageView icon = (ImageView)view.findViewById(R.id.icon);
765bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn            TextView name = (TextView)view.findViewById(R.id.name);
775bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn            TextView description = (TextView)view.findViewById(R.id.description);
785bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn            icon.setImageDrawable(info.info.applicationInfo.loadIcon(getPackageManager()));
795bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn            name.setText(info.label);
805bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn            description.setText(info.info.packageName);
8152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        }
8252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
8352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
8452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    /**
8552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project     * Receives notifications when applications are added/removed.
8652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project     */
8752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    private class ApplicationsIntentReceiver extends BroadcastReceiver {
8852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        @Override
8952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        public void onReceive(Context context, Intent intent) {
9052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            // todo: this is a bit brute force.  We should probably get the action and package name
9152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            //       from the intent and just add to or delete from the mPackageInfoList
9252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            setupAdapter();
9352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        }
9452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
9552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
965bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn    private final static Comparator<MyPackageInfo> sDisplayNameComparator
975bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn            = new Comparator<MyPackageInfo>() {
9852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        public final int
995bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn        compare(MyPackageInfo a, MyPackageInfo b) {
1005bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn            return collator.compare(a.label, b.label);
10152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        }
10252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
10352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        private final Collator   collator = Collator.getInstance();
10452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    };
10552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
10652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    @Override
10752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    protected void onCreate(Bundle icicle) {
10852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        super.onCreate(icicle);
10952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        setupAdapter();
11052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        mHandler= new Handler();
11152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        registerIntentReceivers();
11252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
11352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
1145bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn    @Override
1155bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn    protected void onDestroy() {
1165bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn        super.onDestroy();
1175bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn        if (mRegisteredReceiver != null) {
1185bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn            unregisterReceiver(mRegisteredReceiver);
1195bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn        }
1205bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn    }
1215bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn
12252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    private void setupAdapter() {
12352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        mAdapter = new PackageListAdapter(this);
12452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        setListAdapter(mAdapter);
12552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
12652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
12752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    @Override
12852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    public boolean onCreateOptionsMenu(Menu menu) {
12952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        menu.add(0, 0, 0, "Delete package").setOnMenuItemClickListener(
13052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                new MenuItem.OnMenuItemClickListener() {
13152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            public boolean onMenuItemClick(MenuItem item) {
13252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                deletePackage();
13352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                return true;
13452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            }
13552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        });
13652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        return true;
13752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
13852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
13952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    private void deletePackage() {
14052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        final int curSelection = getSelectedItemPosition();
14152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        if (curSelection >= 0) {
14252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            // todo: verification dialog for package deletion
1435bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn            final MyPackageInfo packageInfo = mAdapter.itemForPosition(curSelection);
14452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            if (packageInfo != null) {
1455bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn                getPackageManager().deletePackage(packageInfo.info.packageName,
14652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                                  new IPackageDeleteObserver.Stub() {
147f9b8546aca4f14956081fff8c3a32a59cd3daa87Kenny Root                    public void packageDeleted(String packageName, int returnCode)
148f9b8546aca4f14956081fff8c3a32a59cd3daa87Kenny Root                            throws RemoteException {
149f9b8546aca4f14956081fff8c3a32a59cd3daa87Kenny Root                        if (returnCode == PackageManager.DELETE_SUCCEEDED) {
15052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                            mPackageInfoList.remove(curSelection);
15152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                            mHandler.post(new Runnable() {
15252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                    public void run() {
15352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                        mAdapter.notifyDataSetChanged();
15452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                    }
15552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                });
15652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
15752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                            // todo: verification dialog for data directory
1585bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn                            final String dataPath = packageInfo.info.applicationInfo.dataDir;
15952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                            // todo: delete the data directory
16052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                        } else {
16152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                            mHandler.post(new Runnable() {
16252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                    public void run() {
16352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                        new AlertDialog.Builder(PackageBrowser.this)
16452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                            .setTitle("Oops")
16552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                            .setMessage("Could not delete package." +
16652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                                "  Maybe it is in /system/app rather than /data/app?")
16752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                            .show();
16852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                    }
16952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                });
17052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
17152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                        }
17252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                    }
17352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                },
17452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                                  0);
17552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            }
17652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        }
17752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
17852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
17952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    private void registerIntentReceivers() {
18052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
18152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
18252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
18352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        filter.addDataScheme("package");
1845bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn        mRegisteredReceiver = new ApplicationsIntentReceiver();
1855bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn        registerReceiver(mRegisteredReceiver, filter);
18652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
18752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
18852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    @Override
1895bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn    protected void onListItemClick(ListView l, View v, int position, long id) {
1905bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn        MyPackageInfo info =
19152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            mAdapter.itemForPosition(position);
19252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        if (info != null) {
19352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            Intent intent = new Intent(
1945bc6141cb29913d344b4a7881956af8b5074f560Dianne Hackborn                null, Uri.fromParts("package", info.info.packageName, null));
19552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            intent.setClass(this, PackageSummary.class);
19652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            startActivity(intent);
19752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        }
19852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
19952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project}
200