• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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