1 /* 2 * Copyright (C) 2013 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.example.android.actionbarcompat.searchview; 18 19 import android.content.pm.ApplicationInfo; 20 import android.content.pm.PackageManager; 21 import android.graphics.drawable.Drawable; 22 import android.os.AsyncTask; 23 import android.os.Bundle; 24 import android.support.v4.app.ListFragment; 25 import android.text.TextUtils; 26 import android.view.LayoutInflater; 27 import android.view.View; 28 import android.view.ViewGroup; 29 import android.widget.BaseAdapter; 30 import android.widget.ImageView; 31 import android.widget.TextView; 32 33 import java.lang.ref.WeakReference; 34 import java.util.ArrayList; 35 import java.util.List; 36 import java.util.regex.Pattern; 37 38 /** 39 * A ListFragment which displays a list of applications currently on the device, with 40 * filtering functionality. 41 */ 42 public class AppListFragment extends ListFragment { 43 44 // Stores the full list of applications installed on the device 45 private final List<ApplicationItem> mInstalledApps = new ArrayList<ApplicationItem>(); 46 47 // Stores the result of the last query 48 private final List<ApplicationItem> mFilteredApps = new ArrayList<ApplicationItem>(); 49 50 private PackageManager mPackageManager; 51 52 @Override onCreate(Bundle savedInstanceState)53 public void onCreate(Bundle savedInstanceState) { 54 super.onCreate(savedInstanceState); 55 56 // Retrieve all of the applications installed on this device 57 mPackageManager = getActivity().getPackageManager(); 58 59 // Start an AsyncTask to load the application's installed on the device 60 new LoadApplicationsTask().execute(); 61 } 62 63 @Override onViewCreated(View view, Bundle savedInstanceState)64 public void onViewCreated(View view, Bundle savedInstanceState) { 65 super.onViewCreated(view, savedInstanceState); 66 67 // Set the ListView's Adapter to display the filtered applications 68 setListAdapter(new AppAdapter()); 69 70 // Set the text which displays when the ListView is empty 71 setEmptyText(getString(R.string.applist_empty_text)); 72 73 // If the installed applications is not loaded yet, hide the list 74 if (mInstalledApps.isEmpty()) { 75 setListShown(false); 76 } 77 } 78 79 /** 80 * Set the query used to filter the installed application's names. 81 * @param query Query to filter against. 82 */ setFilterQuery(String query)83 public void setFilterQuery(String query) { 84 // Fail-fast if the installed apps has not been loaded yet 85 if (mInstalledApps.isEmpty()) { 86 return; 87 } 88 89 // Clear current filtered apps and hide ListView 90 mFilteredApps.clear(); 91 92 if (TextUtils.isEmpty(query)) { 93 // If the query is empty, show all install apps 94 mFilteredApps.addAll(mInstalledApps); 95 } else { 96 // Compile Regex Pattern which will match if the app name contains the query 97 final Pattern p = Pattern.compile(".*" + query + ".*", Pattern.CASE_INSENSITIVE); 98 99 // Iterate through the installed apps to see if their label matches the query 100 for (ApplicationItem application : mInstalledApps) { 101 // If the app label matches the query, add it to the filtered apps list 102 if (p.matcher(application.label).matches()) { 103 mFilteredApps.add(application); 104 } 105 } 106 } 107 108 // Notify the adapter so that it updates the ListView's contents 109 AppAdapter adapter = (AppAdapter) getListAdapter(); 110 adapter.notifyDataSetChanged(); 111 } 112 113 private class AppAdapter extends BaseAdapter { 114 private final LayoutInflater mInflater; 115 AppAdapter()116 AppAdapter() { 117 mInflater = LayoutInflater.from(getActivity()); 118 } 119 120 @Override getCount()121 public int getCount() { 122 return mFilteredApps.size(); 123 } 124 125 @Override getItem(int position)126 public ApplicationItem getItem(int position) { 127 return mFilteredApps.get(position); 128 } 129 130 @Override getItemId(int position)131 public long getItemId(int position) { 132 return position; 133 } 134 135 @Override getView(int position, View convertView, ViewGroup parent)136 public View getView(int position, View convertView, ViewGroup parent) { 137 if (convertView == null) { 138 convertView = mInflater.inflate(R.layout.list_item, parent, false); 139 } 140 141 final ApplicationItem item = getItem(position); 142 143 // Set the application's label on the TextView 144 ((TextView) convertView.findViewById(android.R.id.text1)) 145 .setText(item.label); 146 147 // ImageView to display the application's icon 148 ImageView imageView = (ImageView) convertView.findViewById(R.id.icon); 149 150 // Check the item's drawable reference to see if it is available already 151 Drawable icon = item.drawable != null ? item.drawable.get() : null; 152 153 if (icon != null) { 154 imageView.setImageDrawable(icon); 155 } else { 156 // Start a new AsyncTask which will retrieve the application icon and display it in 157 // the ImageView 158 new ApplicationIconTask(imageView).execute(item); 159 } 160 161 return convertView; 162 } 163 } 164 165 /** 166 * Our model object for each application item. Allows us to load the label async and store the 167 * result for use later (filtering and displaying in the adapter). 168 */ 169 private static class ApplicationItem { 170 final ApplicationInfo applicationInfo; 171 final CharSequence label; 172 WeakReference<Drawable> drawable; 173 ApplicationItem(PackageManager packageManager, ApplicationInfo applicationInfo)174 ApplicationItem(PackageManager packageManager, ApplicationInfo applicationInfo) { 175 this.applicationInfo = applicationInfo; 176 177 // Load and store the app's label using the PackageManager 178 this.label = applicationInfo.loadLabel(packageManager); 179 } 180 } 181 182 /** 183 * Simple AsyncTask which retrieves the installed applications from the {@link PackageManager} 184 * and stores them locally. 185 */ 186 private class LoadApplicationsTask extends AsyncTask<Void, Void, List<ApplicationItem>> { 187 188 @Override doInBackground(Void... voids)189 protected List<ApplicationItem> doInBackground(Void... voids) { 190 // Load all installed applications on the device 191 List<ApplicationInfo> apps = mPackageManager.getInstalledApplications(0); 192 // Create an ArrayList used to store the result 193 ArrayList<ApplicationItem> loadedApps = new ArrayList<ApplicationItem>(); 194 195 // Iterate through the results and create an ApplicationItem instance for each one, 196 // adding them to the returned List. 197 for (ApplicationInfo info : apps) { 198 loadedApps.add(new ApplicationItem(mPackageManager, info)); 199 } 200 201 return loadedApps; 202 } 203 204 @Override onPostExecute(List<ApplicationItem> loadedApps)205 protected void onPostExecute(List<ApplicationItem> loadedApps) { 206 super.onPostExecute(loadedApps); 207 208 // Add the results to the install apps list 209 mInstalledApps.addAll(loadedApps); 210 211 // Reset the query to update the ListView 212 setFilterQuery(null); 213 214 // Make sure the list is shown 215 setListShown(true); 216 } 217 } 218 219 /** 220 * Simple AsyncTask which loads the given application's logo from the {@link PackageManager} and 221 * displays it in the given {@link ImageView} 222 */ 223 private class ApplicationIconTask extends AsyncTask<ApplicationItem, Void, Drawable> { 224 private final ImageView mImageView; 225 ApplicationIconTask(ImageView imageView)226 ApplicationIconTask(ImageView imageView) { 227 mImageView = imageView; 228 } 229 230 @Override doInBackground(ApplicationItem... params)231 protected Drawable doInBackground(ApplicationItem... params) { 232 Drawable icon = null; 233 234 // Check to see that we've been provided one item 235 if (params.length == 1) { 236 ApplicationItem item = params[0]; 237 238 // Load the icon from the PackageManager 239 icon = item.applicationInfo.loadIcon(mPackageManager); 240 241 // Store the icon in a WeakReference so we do not cause a OutOfMemoryError. 242 item.drawable = new WeakReference<Drawable>(icon); 243 } 244 245 return icon; 246 } 247 248 @Override onPostExecute(Drawable icon)249 protected void onPostExecute(Drawable icon) { 250 super.onPostExecute(icon); 251 // Display the icon in the ImageView 252 mImageView.setImageDrawable(icon); 253 } 254 } 255 256 } 257