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