PackageBrowser.java revision 52d4c30ca52320ec92d1d1ddc8db3f07f69c4f98
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;
2752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.net.Uri;
2852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.os.Bundle;
2952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.os.RemoteException;
3052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.os.Handler;
3152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.view.Menu;
3252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.view.MenuItem;
3352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.view.View;
3452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.widget.ListView;
3552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport android.widget.TextView;
3652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
3752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport java.text.Collator;
3852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport java.util.Collections;
3952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport java.util.Comparator;
4052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport java.util.List;
4152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
4252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectpublic class PackageBrowser extends ListActivity
4352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project{
4452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    private PackageListAdapter mAdapter;
4552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    private List<PackageInfo> mPackageInfoList = null;
4652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    private Handler mHandler;
4752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
4852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    public class PackageListAdapter extends ArrayAdapter<PackageInfo>
4952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    {
5052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
5152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        public PackageListAdapter(Context context)
5252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        {
5352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            super(context, android.R.layout.simple_list_item_1);
5452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            mPackageInfoList = context.getPackageManager().getInstalledPackages(0);
5552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            if (mPackageInfoList != null) {
5652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                Collections.sort(mPackageInfoList, sDisplayNameComparator);
5752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            }
5852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            setSource(mPackageInfoList);
5952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        }
6052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
6152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        @Override
6252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        public void bindView(View view, PackageInfo info)
6352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        {
6452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            TextView text = (TextView)view.findViewById(android.R.id.text1);
6552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            text.setText(info.packageName);
6652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        }
6752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
6852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
6952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    /**
7052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project     * Receives notifications when applications are added/removed.
7152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project     */
7252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    private class ApplicationsIntentReceiver extends BroadcastReceiver {
7352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        @Override
7452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        public void onReceive(Context context, Intent intent) {
7552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            // todo: this is a bit brute force.  We should probably get the action and package name
7652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            //       from the intent and just add to or delete from the mPackageInfoList
7752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            setupAdapter();
7852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        }
7952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
8052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
8152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    private final static Comparator sDisplayNameComparator = new Comparator() {
8252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        public final int
8352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        compare(Object a, Object b)
8452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        {
8552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            CharSequence  sa = ((PackageInfo) a).packageName;
8652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            CharSequence  sb = ((PackageInfo) b).packageName;
8752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            return collator.compare(sa, sb);
8852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        }
8952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
9052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        private final Collator   collator = Collator.getInstance();
9152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    };
9252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
9352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    @Override
9452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    protected void onCreate(Bundle icicle) {
9552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        super.onCreate(icicle);
9652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        setupAdapter();
9752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        mHandler= new Handler();
9852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        registerIntentReceivers();
9952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
10052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
10152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    private void setupAdapter() {
10252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        mAdapter = new PackageListAdapter(this);
10352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        setListAdapter(mAdapter);
10452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
10552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
10652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    @Override
10752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    public boolean onCreateOptionsMenu(Menu menu) {
10852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        menu.add(0, 0, 0, "Delete package").setOnMenuItemClickListener(
10952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                new MenuItem.OnMenuItemClickListener() {
11052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            public boolean onMenuItemClick(MenuItem item) {
11152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                deletePackage();
11252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                return true;
11352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            }
11452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        });
11552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        return true;
11652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
11752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
11852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    private void deletePackage() {
11952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        final int curSelection = getSelectedItemPosition();
12052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        if (curSelection >= 0) {
12152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            // todo: verification dialog for package deletion
12252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            final PackageInfo packageInfo = mAdapter.itemForPosition(curSelection);
12352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            if (packageInfo != null) {
12452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                getPackageManager().deletePackage(packageInfo.packageName,
12552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                                  new IPackageDeleteObserver.Stub() {
12652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                    public void packageDeleted(boolean succeeded) throws RemoteException {
12752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                        if (succeeded) {
12852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                            mPackageInfoList.remove(curSelection);
12952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                            mHandler.post(new Runnable() {
13052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                    public void run() {
13152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                        mAdapter.notifyDataSetChanged();
13252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                    }
13352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                });
13452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
13552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                            // todo: verification dialog for data directory
13652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                            final String dataPath = packageInfo.applicationInfo.dataDir;
13752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                            // todo: delete the data directory
13852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                        } else {
13952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                            mHandler.post(new Runnable() {
14052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                    public void run() {
14152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                        new AlertDialog.Builder(PackageBrowser.this)
14252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                            .setTitle("Oops")
14352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                            .setMessage("Could not delete package." +
14452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                                "  Maybe it is in /system/app rather than /data/app?")
14552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                            .show();
14652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                    }
14752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                });
14852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
14952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                        }
15052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                    }
15152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                },
15252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                                                  0);
15352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            }
15452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        }
15552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
15652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
15752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    private void registerIntentReceivers() {
15852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
15952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
16052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
16152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        filter.addDataScheme("package");
16252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        registerReceiver(new ApplicationsIntentReceiver(), filter);
16352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
16452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
16552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    @Override
16652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    protected void onListItemClick(ListView l, View v, int position, long id)
16752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    {
16852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        PackageInfo info =
16952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            mAdapter.itemForPosition(position);
17052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        if (info != null) {
17152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            Intent intent = new Intent(
17252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                null, Uri.fromParts("package", info.packageName, null));
17352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            intent.setClass(this, PackageSummary.class);
17452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            startActivity(intent);
17552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        }
17652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
17752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project}
178