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