LoaderCustomSupport.java revision 109979ea9794aa98665d125ebe6a90448ff65f1f
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; 35109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport android.support.v4.content.IntentCompat; 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; 40109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat; 41aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.text.TextUtils; 42aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.util.Log; 43aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.view.LayoutInflater; 44aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.view.Menu; 45aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.view.MenuInflater; 46aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.view.MenuItem; 47aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.view.View; 48aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.view.ViewGroup; 49aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.widget.ArrayAdapter; 50aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.widget.ImageView; 51aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.widget.ListView; 52aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.widget.TextView; 53109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov 54109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport com.example.android.supportv4.R; 55109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov 56109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport java.io.File; 57109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport java.text.Collator; 58109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport java.util.ArrayList; 59109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport java.util.Collections; 60109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport java.util.Comparator; 61109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport java.util.List; 62aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 63aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn/** 64aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Demonstration of the implementation of a custom Loader. 65aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn */ 66aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornpublic class LoaderCustomSupport extends FragmentActivity { 67aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 68aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn @Override 69aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn protected void onCreate(Bundle savedInstanceState) { 70aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn super.onCreate(savedInstanceState); 71aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 72aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn FragmentManager fm = getSupportFragmentManager(); 73aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 74aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Create the list fragment and add it as our sole content. 75aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (fm.findFragmentById(android.R.id.content) == null) { 76aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn AppListFragment list = new AppListFragment(); 77aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn fm.beginTransaction().add(android.R.id.content, list).commit(); 78aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 79aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 80aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 81aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn//BEGIN_INCLUDE(loader) 82aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn /** 83aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * This class holds the per-item data in our Loader. 84aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn */ 85aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn public static class AppEntry { 86aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn public AppEntry(AppListLoader loader, ApplicationInfo info) { 87aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mLoader = loader; 88aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mInfo = info; 89aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mApkFile = new File(info.sourceDir); 90aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 91aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 92aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn public ApplicationInfo getApplicationInfo() { 93aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn return mInfo; 94aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 95aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 96aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn public String getLabel() { 97aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn return mLabel; 98aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 99aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 100aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn public Drawable getIcon() { 101aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (mIcon == null) { 102aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (mApkFile.exists()) { 103aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mIcon = mInfo.loadIcon(mLoader.mPm); 104aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn return mIcon; 105aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } else { 106aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mMounted = false; 107aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 108aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } else if (!mMounted) { 109aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // If the app wasn't mounted but is now mounted, reload 110aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // its icon. 111aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (mApkFile.exists()) { 112aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mMounted = true; 113aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mIcon = mInfo.loadIcon(mLoader.mPm); 114aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn return mIcon; 115aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 116aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } else { 117aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn return mIcon; 118aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 119aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 120aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn return mLoader.getContext().getResources().getDrawable( 121aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn android.R.drawable.sym_def_app_icon); 122aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 123aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 124aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn @Override public String toString() { 125aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn return mLabel; 126aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 127aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 128aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn void loadLabel(Context context) { 129aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (mLabel == null || !mMounted) { 130aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (!mApkFile.exists()) { 131aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mMounted = false; 132aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mLabel = mInfo.packageName; 133aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } else { 134aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mMounted = true; 135aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn CharSequence label = mInfo.loadLabel(context.getPackageManager()); 136aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mLabel = label != null ? label.toString() : mInfo.packageName; 137aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 138aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 139aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 140aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 141aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn private final AppListLoader mLoader; 142aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn private final ApplicationInfo mInfo; 143aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn private final File mApkFile; 144aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn private String mLabel; 145aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn private Drawable mIcon; 146aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn private boolean mMounted; 147aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 148aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 149aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn /** 150aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Perform alphabetical comparison of application entry objects. 151aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn */ 152aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn public static final Comparator<AppEntry> ALPHA_COMPARATOR = new Comparator<AppEntry>() { 153aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn private final Collator sCollator = Collator.getInstance(); 154aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn @Override 155aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn public int compare(AppEntry object1, AppEntry object2) { 156aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn return sCollator.compare(object1.getLabel(), object2.getLabel()); 157aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 158aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn }; 159aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 160aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn /** 161aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Helper for determining if the configuration has changed in an interesting 162aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * way so we need to rebuild the app list. 163aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn */ 164aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn public static class InterestingConfigChanges { 165aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn final Configuration mLastConfiguration = new Configuration(); 166aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn int mLastDensity; 167aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 168aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn boolean applyNewConfig(Resources res) { 169aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn int configChanges = mLastConfiguration.updateFrom(res.getConfiguration()); 170aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn boolean densityChanged = mLastDensity != res.getDisplayMetrics().densityDpi; 171aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (densityChanged || (configChanges&(ActivityInfo.CONFIG_LOCALE 172109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov |ActivityInfoCompat.CONFIG_UI_MODE|ActivityInfo.CONFIG_SCREEN_LAYOUT)) != 0) { 173aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mLastDensity = res.getDisplayMetrics().densityDpi; 174aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn return true; 175aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 176aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn return false; 177aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 178aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 179aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 180aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn /** 181aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Helper class to look for interesting changes to the installed apps 182aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * so that the loader can be updated. 183aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn */ 184aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn public static class PackageIntentReceiver extends BroadcastReceiver { 185aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn final AppListLoader mLoader; 186aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 187aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn public PackageIntentReceiver(AppListLoader loader) { 188aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mLoader = loader; 189aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); 190aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 191aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 192aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn filter.addDataScheme("package"); 193aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mLoader.getContext().registerReceiver(this, filter); 194aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Register for events related to sdcard installation. 195aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn IntentFilter sdFilter = new IntentFilter(); 196109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov sdFilter.addAction(IntentCompat.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); 197109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov sdFilter.addAction(IntentCompat.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 198aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mLoader.getContext().registerReceiver(this, sdFilter); 199aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 200aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 201aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn @Override public void onReceive(Context context, Intent intent) { 202aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Tell the loader about the change. 203aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mLoader.onContentChanged(); 204aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 205aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 206aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 207aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn /** 208aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * A custom Loader that loads all of the installed applications. 209aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn */ 210aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn public static class AppListLoader extends AsyncTaskLoader<List<AppEntry>> { 211aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn final InterestingConfigChanges mLastConfig = new InterestingConfigChanges(); 212aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn final PackageManager mPm; 213aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 214aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn List<AppEntry> mApps; 215aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn PackageIntentReceiver mPackageObserver; 216aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 217aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn public AppListLoader(Context context) { 218aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn super(context); 219aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 220aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Retrieve the package manager for later use; note we don't 221aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // use 'context' directly but instead the save global application 222aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // context returned by getContext(). 223aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mPm = getContext().getPackageManager(); 224aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 225aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 226aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn /** 227aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * This is where the bulk of our work is done. This function is 228aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * called in a background thread and should generate a new set of 229aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * data to be published by the loader. 230aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn */ 231aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn @Override public List<AppEntry> loadInBackground() { 232aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Retrieve all known applications. 233aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn List<ApplicationInfo> apps = mPm.getInstalledApplications( 234aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn PackageManager.GET_UNINSTALLED_PACKAGES | 235aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn PackageManager.GET_DISABLED_COMPONENTS); 236aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (apps == null) { 237aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn apps = new ArrayList<ApplicationInfo>(); 238aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 239aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 240aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn final Context context = getContext(); 241aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 242aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Create corresponding array of entries and load their labels. 243aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn List<AppEntry> entries = new ArrayList<AppEntry>(apps.size()); 244aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn for (int i=0; i<apps.size(); i++) { 245aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn AppEntry entry = new AppEntry(this, apps.get(i)); 246aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn entry.loadLabel(context); 247aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn entries.add(entry); 248aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 249aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 250aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Sort the list. 251aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn Collections.sort(entries, ALPHA_COMPARATOR); 252aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 253aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Done! 254aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn return entries; 255aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 256aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 257aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn /** 258aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Called when there is new data to deliver to the client. The 259aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * super class will take care of delivering it; the implementation 260aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * here just adds a little more logic. 261aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn */ 262aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn @Override public void deliverResult(List<AppEntry> apps) { 263aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (isReset()) { 264aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // An async query came in while the loader is stopped. We 265aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // don't need the result. 266aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (apps != null) { 267aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn onReleaseResources(apps); 268aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 269aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 270aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn List<AppEntry> oldApps = apps; 271aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mApps = apps; 272aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 273aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (isStarted()) { 274aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // If the Loader is currently started, we can immediately 275aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // deliver its results. 276aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn super.deliverResult(apps); 277aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 278aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 279aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // At this point we can release the resources associated with 280aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // 'oldApps' if needed; now that the new result is delivered we 281aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // know that it is no longer in use. 282aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (oldApps != null) { 283aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn onReleaseResources(oldApps); 284aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 285aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 286aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 287aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn /** 288aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Handles a request to start the Loader. 289aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn */ 290aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn @Override protected void onStartLoading() { 291aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (mApps != null) { 292aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // If we currently have a result available, deliver it 293aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // immediately. 294aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn deliverResult(mApps); 295aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 296aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 297aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Start watching for changes in the app data. 298aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (mPackageObserver == null) { 299aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mPackageObserver = new PackageIntentReceiver(this); 300aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 301aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 302aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Has something interesting in the configuration changed since we 303aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // last built the app list? 304aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn boolean configChange = mLastConfig.applyNewConfig(getContext().getResources()); 305aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 306aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (takeContentChanged() || mApps == null || configChange) { 307aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // If the data has changed since the last time it was loaded 308aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // or is not currently available, start a load. 309aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn forceLoad(); 310aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 311aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 312aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 313aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn /** 314aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Handles a request to stop the Loader. 315aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn */ 316aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn @Override protected void onStopLoading() { 317aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Attempt to cancel the current load task if possible. 318aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn cancelLoad(); 319aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 320aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 321aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn /** 322aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Handles a request to cancel a load. 323aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn */ 324aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn @Override public void onCanceled(List<AppEntry> apps) { 325aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn super.onCanceled(apps); 326aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 327aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // At this point we can release the resources associated with 'apps' 328aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // if needed. 329aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn onReleaseResources(apps); 330aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 331aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 332aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn /** 333aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Handles a request to completely reset the Loader. 334aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn */ 335aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn @Override protected void onReset() { 336aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn super.onReset(); 337aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 338aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Ensure the loader is stopped 339aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn onStopLoading(); 340aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 341aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // At this point we can release the resources associated with 'apps' 342aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // if needed. 343aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (mApps != null) { 344aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn onReleaseResources(mApps); 345aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mApps = null; 346aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 347aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 348aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Stop monitoring for changes. 349aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (mPackageObserver != null) { 350aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn getContext().unregisterReceiver(mPackageObserver); 351aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mPackageObserver = null; 352aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 353aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 354aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 355aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn /** 356aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Helper function to take care of releasing resources associated 357aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * with an actively loaded data set. 358aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn */ 359aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn protected void onReleaseResources(List<AppEntry> apps) { 360aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // For a simple List<> there is nothing to do. For something 361aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // like a Cursor, we would close it here. 362aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 363aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 364aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn//END_INCLUDE(loader) 365aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 366aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn//BEGIN_INCLUDE(fragment) 367aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn public static class AppListAdapter extends ArrayAdapter<AppEntry> { 368aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn private final LayoutInflater mInflater; 369aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 370aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn public AppListAdapter(Context context) { 371aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn super(context, android.R.layout.simple_list_item_2); 372aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 373aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 374aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 375aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn public void setData(List<AppEntry> data) { 376aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn clear(); 377aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (data != null) { 378109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov for (AppEntry appEntry : data) { 379109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov add(appEntry); 380109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov } 381aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 382aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 383aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 384aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn /** 385aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Populate new items in the list. 386aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn */ 387aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn @Override public View getView(int position, View convertView, ViewGroup parent) { 388aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn View view; 389aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 390aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (convertView == null) { 391aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn view = mInflater.inflate(R.layout.list_item_icon_text, parent, false); 392aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } else { 393aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn view = convertView; 394aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 395aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 396aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn AppEntry item = getItem(position); 397aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn ((ImageView)view.findViewById(R.id.icon)).setImageDrawable(item.getIcon()); 398aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn ((TextView)view.findViewById(R.id.text)).setText(item.getLabel()); 399aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 400aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn return view; 401aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 402aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 403aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 404aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn public static class AppListFragment extends ListFragment 405109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov implements LoaderManager.LoaderCallbacks<List<AppEntry>> { 406aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 407aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // This is the Adapter being used to display the list's data. 408aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn AppListAdapter mAdapter; 409aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 410aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // If non-null, this is the current filter the user has provided. 411aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn String mCurFilter; 412aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 413109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov OnQueryTextListenerCompat mOnQueryTextListenerCompat; 414109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov 415aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn @Override public void onActivityCreated(Bundle savedInstanceState) { 416aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn super.onActivityCreated(savedInstanceState); 417aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 418aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Give some text to display if there is no data. In a real 419aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // application this would come from a resource. 420aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn setEmptyText("No applications"); 421aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 422aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // We have a menu item to show in action bar. 423aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn setHasOptionsMenu(true); 424aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 425aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Create an empty adapter we will use to display the loaded data. 426aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mAdapter = new AppListAdapter(getActivity()); 427aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn setListAdapter(mAdapter); 428aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 429aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Start out with a progress indicator. 430aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn setListShown(false); 431aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 432aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Prepare the loader. Either re-connect with an existing one, 433aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // or start a new one. 434aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn getLoaderManager().initLoader(0, null, this); 435aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 436aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 437aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 438aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Place an action bar item for searching. 439aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn MenuItem item = menu.add("Search"); 440aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn item.setIcon(android.R.drawable.ic_menu_search); 441109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); 442109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov View searchView = SearchViewCompat.newSearchView(getActivity()); 443109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov if (searchView != null) { 444109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov SearchViewCompat.setOnQueryTextListener(searchView, 445109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov new OnQueryTextListenerCompat() { 446109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov @Override 447109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov public boolean onQueryTextChange(String newText) { 448109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov // Called when the action bar search text has changed. Since this 449109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov // is a simple array adapter, we can just have it do the filtering. 450109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; 451109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov mAdapter.getFilter().filter(mCurFilter); 452109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov return true; 453109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov } 454109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov }); 455109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov MenuItemCompat.setActionView(item, searchView); 456109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov } 457aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 458aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 459aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn @Override public void onListItemClick(ListView l, View v, int position, long id) { 460aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Insert desired behavior here. 461aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn Log.i("LoaderCustom", "Item clicked: " + id); 462aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 463aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 464aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn @Override public Loader<List<AppEntry>> onCreateLoader(int id, Bundle args) { 465aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // This is called when a new Loader needs to be created. This 466aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // sample only has one Loader with no arguments, so it is simple. 467aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn return new AppListLoader(getActivity()); 468aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 469aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 470aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn @Override public void onLoadFinished(Loader<List<AppEntry>> loader, List<AppEntry> data) { 471aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Set the new data in the adapter. 472aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mAdapter.setData(data); 473aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 474aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // The list should now be shown. 475aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (isResumed()) { 476aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn setListShown(true); 477aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } else { 478aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn setListShownNoAnimation(true); 479aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 480aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 481aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 482aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn @Override public void onLoaderReset(Loader<List<AppEntry>> loader) { 483aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Clear the data in the adapter. 484aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn mAdapter.setData(null); 485aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 486aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 487aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn//END_INCLUDE(fragment) 488aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn} 489