LoaderCustomSupport.java revision ddffc06960e054e3e4f4eb468360e73053c7cbab
1aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn/*
2aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Copyright (C) 2010 The Android Open Source Project
3aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn *
4aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License");
5aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * you may not use this file except in compliance with the License.
6aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * You may obtain a copy of the License at
7aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn *
8aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn *      http://www.apache.org/licenses/LICENSE-2.0
9aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn *
10aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Unless required by applicable law or agreed to in writing, software
11aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS,
12aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * See the License for the specific language governing permissions and
14aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * limitations under the License.
15aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn */
16aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
17aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornpackage com.example.android.supportv4.app;
18aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
19aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.content.BroadcastReceiver;
20aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.content.Context;
21aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.content.Intent;
22aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.content.IntentFilter;
23aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.content.pm.ActivityInfo;
24aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.content.pm.ApplicationInfo;
25aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.content.pm.PackageManager;
26aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.content.res.Configuration;
27aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.content.res.Resources;
28aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.graphics.drawable.Drawable;
29aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.os.Bundle;
30aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.support.v4.app.FragmentActivity;
31aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.support.v4.app.FragmentManager;
32aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.support.v4.app.ListFragment;
33aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.support.v4.app.LoaderManager;
34aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.support.v4.content.AsyncTaskLoader;
3567949f5f3bc1f721fa5f63250f0fd74a44f5381fAurimas Liutikasimport android.support.v4.content.ContextCompat;
36aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.support.v4.content.Loader;
37109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport android.support.v4.content.pm.ActivityInfoCompat;
38109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport android.support.v4.view.MenuItemCompat;
39109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport android.support.v4.widget.SearchViewCompat;
40aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.text.TextUtils;
41aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.util.Log;
42aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.view.LayoutInflater;
43aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.view.Menu;
44aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.view.MenuInflater;
45aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.view.MenuItem;
46aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.view.View;
47aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.view.ViewGroup;
48aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.widget.ArrayAdapter;
49aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.widget.ImageView;
50aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.widget.ListView;
51aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.widget.TextView;
52109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov
53109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport com.example.android.supportv4.R;
54109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov
55109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport java.io.File;
56109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport java.text.Collator;
57109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport java.util.ArrayList;
58109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport java.util.Collections;
59109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport java.util.Comparator;
60109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport java.util.List;
61aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
62aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn/**
63aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Demonstration of the implementation of a custom Loader.
64aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn */
65aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornpublic class LoaderCustomSupport extends FragmentActivity {
66aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
67aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    @Override
68aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    protected void onCreate(Bundle savedInstanceState) {
69aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        super.onCreate(savedInstanceState);
70aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
71aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        FragmentManager fm = getSupportFragmentManager();
72aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
73aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        // Create the list fragment and add it as our sole content.
74aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        if (fm.findFragmentById(android.R.id.content) == null) {
75aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            AppListFragment list = new AppListFragment();
76aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            fm.beginTransaction().add(android.R.id.content, list).commit();
77aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
78aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    }
79aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
80aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn//BEGIN_INCLUDE(loader)
81aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    /**
82aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     * This class holds the per-item data in our Loader.
83aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     */
84aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    public static class AppEntry {
85aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        public AppEntry(AppListLoader loader, ApplicationInfo info) {
86aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mLoader = loader;
87aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mInfo = info;
88aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mApkFile = new File(info.sourceDir);
89aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
90aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
91aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        public ApplicationInfo getApplicationInfo() {
92aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            return mInfo;
93aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
94aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
95aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        public String getLabel() {
96aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            return mLabel;
97aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
98aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
99aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        public Drawable getIcon() {
100aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            if (mIcon == null) {
101aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                if (mApkFile.exists()) {
102aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                    mIcon = mInfo.loadIcon(mLoader.mPm);
103aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                    return mIcon;
104aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                } else {
105aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                    mMounted = false;
106aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                }
107aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            } else if (!mMounted) {
108aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                // If the app wasn't mounted but is now mounted, reload
109aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                // its icon.
110aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                if (mApkFile.exists()) {
111aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                    mMounted = true;
112aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                    mIcon = mInfo.loadIcon(mLoader.mPm);
113aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                    return mIcon;
114aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                }
115aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            } else {
116aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                return mIcon;
117aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
118aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
11967949f5f3bc1f721fa5f63250f0fd74a44f5381fAurimas Liutikas            return ContextCompat.getDrawable(
12067949f5f3bc1f721fa5f63250f0fd74a44f5381fAurimas Liutikas                    mLoader.getContext(), android.R.drawable.sym_def_app_icon);
121aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
122aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
123aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override public String toString() {
124aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            return mLabel;
125aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
126aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
127aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        void loadLabel(Context context) {
128aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            if (mLabel == null || !mMounted) {
129aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                if (!mApkFile.exists()) {
130aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                    mMounted = false;
131aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                    mLabel = mInfo.packageName;
132aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                } else {
133aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                    mMounted = true;
134aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                    CharSequence label = mInfo.loadLabel(context.getPackageManager());
135aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                    mLabel = label != null ? label.toString() : mInfo.packageName;
136aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                }
137aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
138aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
139aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
140aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        private final AppListLoader mLoader;
141aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        private final ApplicationInfo mInfo;
142aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        private final File mApkFile;
143aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        private String mLabel;
144aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        private Drawable mIcon;
145aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        private boolean mMounted;
146aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    }
147aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
148aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    /**
149aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     * Perform alphabetical comparison of application entry objects.
150aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     */
151aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    public static final Comparator<AppEntry> ALPHA_COMPARATOR = new Comparator<AppEntry>() {
152aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        private final Collator sCollator = Collator.getInstance();
153aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override
154aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        public int compare(AppEntry object1, AppEntry object2) {
155aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            return sCollator.compare(object1.getLabel(), object2.getLabel());
156aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
157aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    };
158aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
159aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    /**
160aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     * Helper for determining if the configuration has changed in an interesting
161aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     * way so we need to rebuild the app list.
162aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     */
163aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    public static class InterestingConfigChanges {
164aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        final Configuration mLastConfiguration = new Configuration();
165aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        int mLastDensity;
166aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
167aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        boolean applyNewConfig(Resources res) {
168aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            int configChanges = mLastConfiguration.updateFrom(res.getConfiguration());
169aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            boolean densityChanged = mLastDensity != res.getDisplayMetrics().densityDpi;
170aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            if (densityChanged || (configChanges&(ActivityInfo.CONFIG_LOCALE
171109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov                    |ActivityInfoCompat.CONFIG_UI_MODE|ActivityInfo.CONFIG_SCREEN_LAYOUT)) != 0) {
172aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                mLastDensity = res.getDisplayMetrics().densityDpi;
173aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                return true;
174aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
175aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            return false;
176aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
177aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    }
178aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
179aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    /**
180aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     * Helper class to look for interesting changes to the installed apps
181aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     * so that the loader can be updated.
182aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     */
183aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    public static class PackageIntentReceiver extends BroadcastReceiver {
184aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        final AppListLoader mLoader;
185aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
186aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        public PackageIntentReceiver(AppListLoader loader) {
187aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mLoader = loader;
188aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
189aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
190aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
191aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            filter.addDataScheme("package");
192aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mLoader.getContext().registerReceiver(this, filter);
193aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Register for events related to sdcard installation.
194aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            IntentFilter sdFilter = new IntentFilter();
195ddffc06960e054e3e4f4eb468360e73053c7cbabAurimas Liutikas            sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
196ddffc06960e054e3e4f4eb468360e73053c7cbabAurimas Liutikas            sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
197aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mLoader.getContext().registerReceiver(this, sdFilter);
198aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
199aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
200aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override public void onReceive(Context context, Intent intent) {
201aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Tell the loader about the change.
202aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mLoader.onContentChanged();
203aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
204aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    }
205aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
206aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    /**
207aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     * A custom Loader that loads all of the installed applications.
208aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     */
209aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    public static class AppListLoader extends AsyncTaskLoader<List<AppEntry>> {
210aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        final InterestingConfigChanges mLastConfig = new InterestingConfigChanges();
211aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        final PackageManager mPm;
212aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
213aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        List<AppEntry> mApps;
214aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        PackageIntentReceiver mPackageObserver;
215aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
216aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        public AppListLoader(Context context) {
217aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            super(context);
218aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
219aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Retrieve the package manager for later use; note we don't
220aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // use 'context' directly but instead the save global application
221aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // context returned by getContext().
222aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mPm = getContext().getPackageManager();
223aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
224aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
225aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        /**
226aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         * This is where the bulk of our work is done.  This function is
227aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         * called in a background thread and should generate a new set of
228aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         * data to be published by the loader.
229aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         */
230aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override public List<AppEntry> loadInBackground() {
231aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Retrieve all known applications.
232aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            List<ApplicationInfo> apps = mPm.getInstalledApplications(
23367949f5f3bc1f721fa5f63250f0fd74a44f5381fAurimas Liutikas                    PackageManager.MATCH_UNINSTALLED_PACKAGES
23467949f5f3bc1f721fa5f63250f0fd74a44f5381fAurimas Liutikas                            | PackageManager.MATCH_DISABLED_COMPONENTS);
235aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            if (apps == null) {
236aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                apps = new ArrayList<ApplicationInfo>();
237aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
238aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
239aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            final Context context = getContext();
240aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
241aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Create corresponding array of entries and load their labels.
242aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            List<AppEntry> entries = new ArrayList<AppEntry>(apps.size());
24367949f5f3bc1f721fa5f63250f0fd74a44f5381fAurimas Liutikas            for (int i = 0; i < apps.size(); i++) {
244aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                AppEntry entry = new AppEntry(this, apps.get(i));
245aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                entry.loadLabel(context);
246aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                entries.add(entry);
247aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
248aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
249aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Sort the list.
250aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            Collections.sort(entries, ALPHA_COMPARATOR);
251aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
252aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Done!
253aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            return entries;
254aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
255aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
256aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        /**
257aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         * Called when there is new data to deliver to the client.  The
258aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         * super class will take care of delivering it; the implementation
259aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         * here just adds a little more logic.
260aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         */
261aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override public void deliverResult(List<AppEntry> apps) {
262aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            if (isReset()) {
263aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                // An async query came in while the loader is stopped.  We
264aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                // don't need the result.
265aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                if (apps != null) {
266aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                    onReleaseResources(apps);
267aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                }
268aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
269aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            List<AppEntry> oldApps = apps;
270aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mApps = apps;
271aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
272aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            if (isStarted()) {
273aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                // If the Loader is currently started, we can immediately
274aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                // deliver its results.
275aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                super.deliverResult(apps);
276aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
277aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
278aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // At this point we can release the resources associated with
279aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // 'oldApps' if needed; now that the new result is delivered we
280aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // know that it is no longer in use.
281aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            if (oldApps != null) {
282aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                onReleaseResources(oldApps);
283aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
284aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
285aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
286aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        /**
287aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         * Handles a request to start the Loader.
288aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         */
289aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override protected void onStartLoading() {
290aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            if (mApps != null) {
291aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                // If we currently have a result available, deliver it
292aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                // immediately.
293aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                deliverResult(mApps);
294aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
295aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
296aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Start watching for changes in the app data.
297aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            if (mPackageObserver == null) {
298aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                mPackageObserver = new PackageIntentReceiver(this);
299aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
300aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
301aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Has something interesting in the configuration changed since we
302aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // last built the app list?
303aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            boolean configChange = mLastConfig.applyNewConfig(getContext().getResources());
304aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
305aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            if (takeContentChanged() || mApps == null || configChange) {
306aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                // If the data has changed since the last time it was loaded
307aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                // or is not currently available, start a load.
308aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                forceLoad();
309aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
310aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
311aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
312aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        /**
313aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         * Handles a request to stop the Loader.
314aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         */
315aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override protected void onStopLoading() {
316aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Attempt to cancel the current load task if possible.
317aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            cancelLoad();
318aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
319aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
320aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        /**
321aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         * Handles a request to cancel a load.
322aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         */
323aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override public void onCanceled(List<AppEntry> apps) {
324aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            super.onCanceled(apps);
325aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
326aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // At this point we can release the resources associated with 'apps'
327aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // if needed.
328aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            onReleaseResources(apps);
329aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
330aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
331aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        /**
332aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         * Handles a request to completely reset the Loader.
333aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         */
334aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override protected void onReset() {
335aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            super.onReset();
336aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
337aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Ensure the loader is stopped
338aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            onStopLoading();
339aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
340aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // At this point we can release the resources associated with 'apps'
341aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // if needed.
342aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            if (mApps != null) {
343aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                onReleaseResources(mApps);
344aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                mApps = null;
345aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
346aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
347aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Stop monitoring for changes.
348aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            if (mPackageObserver != null) {
349aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                getContext().unregisterReceiver(mPackageObserver);
350aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                mPackageObserver = null;
351aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
352aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
353aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
354aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        /**
355aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         * Helper function to take care of releasing resources associated
356aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         * with an actively loaded data set.
357aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         */
358aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        protected void onReleaseResources(List<AppEntry> apps) {
359aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // For a simple List<> there is nothing to do.  For something
360aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // like a Cursor, we would close it here.
361aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
362aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    }
363aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn//END_INCLUDE(loader)
364aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
365aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn//BEGIN_INCLUDE(fragment)
366aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    public static class AppListAdapter extends ArrayAdapter<AppEntry> {
367aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        private final LayoutInflater mInflater;
368aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
369aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        public AppListAdapter(Context context) {
370aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            super(context, android.R.layout.simple_list_item_2);
371aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
372aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
373aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
374aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        public void setData(List<AppEntry> data) {
375aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            clear();
376aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            if (data != null) {
377109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov                for (AppEntry appEntry : data) {
378109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov                    add(appEntry);
379109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov                }
380aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
381aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
382aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
383aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        /**
384aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         * Populate new items in the list.
385aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn         */
386aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override public View getView(int position, View convertView, ViewGroup parent) {
387aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            View view;
388aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
389aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            if (convertView == null) {
390aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                view = mInflater.inflate(R.layout.list_item_icon_text, parent, false);
391aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            } else {
392aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                view = convertView;
393aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
394aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
395aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            AppEntry item = getItem(position);
396aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            ((ImageView)view.findViewById(R.id.icon)).setImageDrawable(item.getIcon());
397aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            ((TextView)view.findViewById(R.id.text)).setText(item.getLabel());
398aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
399aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            return view;
400aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
401aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    }
402aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
403aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    public static class AppListFragment extends ListFragment
404109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov            implements LoaderManager.LoaderCallbacks<List<AppEntry>> {
405aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
406aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        // This is the Adapter being used to display the list's data.
407aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        AppListAdapter mAdapter;
408aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
409aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        // If non-null, this is the current filter the user has provided.
410aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        String mCurFilter;
411aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
412aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override public void onActivityCreated(Bundle savedInstanceState) {
413aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            super.onActivityCreated(savedInstanceState);
414aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
415aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Give some text to display if there is no data.  In a real
416aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // application this would come from a resource.
417aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            setEmptyText("No applications");
418aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
419aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // We have a menu item to show in action bar.
420aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            setHasOptionsMenu(true);
421aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
422aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Create an empty adapter we will use to display the loaded data.
423aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mAdapter = new AppListAdapter(getActivity());
424aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            setListAdapter(mAdapter);
425aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
426aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Start out with a progress indicator.
427aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            setListShown(false);
428aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
429aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Prepare the loader.  Either re-connect with an existing one,
430aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // or start a new one.
431aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            getLoaderManager().initLoader(0, null, this);
432aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
433aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
434aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
435aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Place an action bar item for searching.
436aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            MenuItem item = menu.add("Search");
437aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            item.setIcon(android.R.drawable.ic_menu_search);
4386a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn            MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM
4396a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn                    | MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
4409243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn            final View searchView = SearchViewCompat.newSearchView(getActivity());
441109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov            if (searchView != null) {
442109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov                SearchViewCompat.setOnQueryTextListener(searchView,
4439c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas                        new SearchViewCompat.OnQueryTextListener() {
4449c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas                            @Override
4459c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas                            public boolean onQueryTextChange(String newText) {
4469c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas                                // Called when the action bar search text has changed.  Since this
4479c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas                                // is a simple array adapter, we can just have it do the filtering.
4489c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas                                mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
4499c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas                                mAdapter.getFilter().filter(mCurFilter);
4509c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas                                return true;
4519c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas                            }
4529c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas
4539c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas                            @Override
4549c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas                            public boolean onQueryTextSubmit(String query) {
4559c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas                                return false;
4569c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas                            }
4579c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas                        });
4589243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn                SearchViewCompat.setOnCloseListener(searchView,
4599c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas                        new SearchViewCompat.OnCloseListener() {
4609243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn                            @Override
4619243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn                            public boolean onClose() {
4629243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn                                if (!TextUtils.isEmpty(SearchViewCompat.getQuery(searchView))) {
4639243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn                                    SearchViewCompat.setQuery(searchView, null, true);
4649243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn                                }
4659243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn                                return true;
4669243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn                            }
4679c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas                        });
468109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov                MenuItemCompat.setActionView(item, searchView);
469109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov            }
470aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
471aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
472aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override public void onListItemClick(ListView l, View v, int position, long id) {
473aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Insert desired behavior here.
474aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            Log.i("LoaderCustom", "Item clicked: " + id);
475aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
476aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
477aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override public Loader<List<AppEntry>> onCreateLoader(int id, Bundle args) {
478aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // This is called when a new Loader needs to be created.  This
479aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // sample only has one Loader with no arguments, so it is simple.
480aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            return new AppListLoader(getActivity());
481aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
482aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
483aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override public void onLoadFinished(Loader<List<AppEntry>> loader, List<AppEntry> data) {
484aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Set the new data in the adapter.
485aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mAdapter.setData(data);
486aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
487aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // The list should now be shown.
488aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            if (isResumed()) {
489aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                setListShown(true);
490aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            } else {
491aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                setListShownNoAnimation(true);
492aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
493aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
494aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
495aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override public void onLoaderReset(Loader<List<AppEntry>> loader) {
496aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            // Clear the data in the adapter.
497aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mAdapter.setData(null);
498aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
499aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    }
500aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn//END_INCLUDE(fragment)
501aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn}
502