1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.development; 18 19 import android.app.AlertDialog; 20 import android.app.ListActivity; 21 import android.content.Context; 22 import android.content.pm.IPackageDeleteObserver; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.content.BroadcastReceiver; 26 import android.content.pm.PackageInfo; 27 import android.content.pm.PackageManager; 28 import android.net.Uri; 29 import android.os.Bundle; 30 import android.os.RemoteException; 31 import android.os.Handler; 32 import android.view.Menu; 33 import android.view.MenuItem; 34 import android.view.View; 35 import android.widget.ImageView; 36 import android.widget.ListView; 37 import android.widget.TextView; 38 39 import java.text.Collator; 40 import java.util.ArrayList; 41 import java.util.Collections; 42 import java.util.Comparator; 43 import java.util.List; 44 45 public class PackageBrowser extends ListActivity { 46 static class MyPackageInfo { 47 PackageInfo info; 48 String label; 49 } 50 51 private PackageListAdapter mAdapter; 52 private List<MyPackageInfo> mPackageInfoList = new ArrayList<MyPackageInfo>(); 53 private Handler mHandler; 54 private BroadcastReceiver mRegisteredReceiver; 55 56 public class PackageListAdapter extends ArrayAdapter<MyPackageInfo> { 57 58 public PackageListAdapter(Context context) { 59 super(context, R.layout.package_list_item); 60 List<PackageInfo> pkgs = context.getPackageManager().getInstalledPackages(0); 61 for (int i=0; i<pkgs.size(); i++) { 62 MyPackageInfo info = new MyPackageInfo(); 63 info.info = pkgs.get(i); 64 info.label = info.info.applicationInfo.loadLabel(getPackageManager()).toString(); 65 mPackageInfoList.add(info); 66 } 67 if (mPackageInfoList != null) { 68 Collections.sort(mPackageInfoList, sDisplayNameComparator); 69 } 70 setSource(mPackageInfoList); 71 } 72 73 @Override 74 public void bindView(View view, MyPackageInfo info) { 75 ImageView icon = (ImageView)view.findViewById(R.id.icon); 76 TextView name = (TextView)view.findViewById(R.id.name); 77 TextView description = (TextView)view.findViewById(R.id.description); 78 icon.setImageDrawable(info.info.applicationInfo.loadIcon(getPackageManager())); 79 name.setText(info.label); 80 description.setText(info.info.packageName); 81 } 82 } 83 84 /** 85 * Receives notifications when applications are added/removed. 86 */ 87 private class ApplicationsIntentReceiver extends BroadcastReceiver { 88 @Override 89 public void onReceive(Context context, Intent intent) { 90 // todo: this is a bit brute force. We should probably get the action and package name 91 // from the intent and just add to or delete from the mPackageInfoList 92 setupAdapter(); 93 } 94 } 95 96 private final static Comparator<MyPackageInfo> sDisplayNameComparator 97 = new Comparator<MyPackageInfo>() { 98 public final int 99 compare(MyPackageInfo a, MyPackageInfo b) { 100 return collator.compare(a.label, b.label); 101 } 102 103 private final Collator collator = Collator.getInstance(); 104 }; 105 106 @Override 107 protected void onCreate(Bundle icicle) { 108 super.onCreate(icicle); 109 setupAdapter(); 110 mHandler= new Handler(); 111 registerIntentReceivers(); 112 } 113 114 @Override 115 protected void onDestroy() { 116 super.onDestroy(); 117 if (mRegisteredReceiver != null) { 118 unregisterReceiver(mRegisteredReceiver); 119 } 120 } 121 122 private void setupAdapter() { 123 mAdapter = new PackageListAdapter(this); 124 setListAdapter(mAdapter); 125 } 126 127 @Override 128 public boolean onCreateOptionsMenu(Menu menu) { 129 menu.add(0, 0, 0, "Delete package").setOnMenuItemClickListener( 130 new MenuItem.OnMenuItemClickListener() { 131 public boolean onMenuItemClick(MenuItem item) { 132 deletePackage(); 133 return true; 134 } 135 }); 136 return true; 137 } 138 139 private void deletePackage() { 140 final int curSelection = getSelectedItemPosition(); 141 if (curSelection >= 0) { 142 // todo: verification dialog for package deletion 143 final MyPackageInfo packageInfo = mAdapter.itemForPosition(curSelection); 144 if (packageInfo != null) { 145 getPackageManager().deletePackage(packageInfo.info.packageName, 146 new IPackageDeleteObserver.Stub() { 147 public void packageDeleted(String packageName, int returnCode) 148 throws RemoteException { 149 if (returnCode == PackageManager.DELETE_SUCCEEDED) { 150 mPackageInfoList.remove(curSelection); 151 mHandler.post(new Runnable() { 152 public void run() { 153 mAdapter.notifyDataSetChanged(); 154 } 155 }); 156 157 // todo: verification dialog for data directory 158 final String dataPath = packageInfo.info.applicationInfo.dataDir; 159 // todo: delete the data directory 160 } else { 161 mHandler.post(new Runnable() { 162 public void run() { 163 new AlertDialog.Builder(PackageBrowser.this) 164 .setTitle("Oops") 165 .setMessage("Could not delete package." + 166 " Maybe it is in /system/app rather than /data/app?") 167 .show(); 168 } 169 }); 170 171 } 172 } 173 }, 174 0); 175 } 176 } 177 } 178 179 private void registerIntentReceivers() { 180 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); 181 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 182 filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 183 filter.addDataScheme("package"); 184 mRegisteredReceiver = new ApplicationsIntentReceiver(); 185 registerReceiver(mRegisteredReceiver, filter); 186 } 187 188 @Override 189 protected void onListItemClick(ListView l, View v, int position, long id) { 190 MyPackageInfo info = 191 mAdapter.itemForPosition(position); 192 if (info != null) { 193 Intent intent = new Intent( 194 null, Uri.fromParts("package", info.info.packageName, null)); 195 intent.setClass(this, PackageSummary.class); 196 startActivity(intent); 197 } 198 } 199 } 200