13e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert/* 23e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Copyright (C) 2009 The Android Open Source Project 33e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 43e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); 53e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * you may not use this file except in compliance with the License. 63e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * You may obtain a copy of the License at 73e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 83e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0 93e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Unless required by applicable law or agreed to in writing, software 113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS, 123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * See the License for the specific language governing permissions and 143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * limitations under the License. 153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertpackage com.android.quicksearchbox; 183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 19e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwoodimport com.android.quicksearchbox.util.CachedLater; 20516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwoodimport com.android.quicksearchbox.util.NamedTask; 21516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwoodimport com.android.quicksearchbox.util.NamedTaskExecutor; 22e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwoodimport com.android.quicksearchbox.util.Now; 23e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwoodimport com.android.quicksearchbox.util.NowOrLater; 242353e9c002c45c0adc8a979a49ff317cae5838b8Bjorn Bringertimport com.android.quicksearchbox.util.Util; 252353e9c002c45c0adc8a979a49ff317cae5838b8Bjorn Bringert 263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.ContentResolver; 273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.Context; 28e1fc4581ebab65220a82bcdb3272b4eb85453837Bjorn Bringertimport android.content.pm.PackageManager; 293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.pm.PackageManager.NameNotFoundException; 303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.res.Resources; 313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.graphics.drawable.Drawable; 323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.net.Uri; 33e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwoodimport android.os.Handler; 343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.text.TextUtils; 353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.util.Log; 363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport java.io.FileNotFoundException; 383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport java.io.IOException; 393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport java.io.InputStream; 403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport java.util.List; 413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert/** 433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Loads icons from other packages. 443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 45fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * Code partly stolen from {@link ContentResolver} and android.app.SuggestionsAdapter. 46fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert */ 473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertpublic class PackageIconLoader implements IconLoader { 483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private static final boolean DBG = false; 503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private static final String TAG = "QSB.PackageIconLoader"; 513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5225f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert private final Context mContext; 5325f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert 5425f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert private final String mPackageName; 5525f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert 5625f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert private Context mPackageContext; 573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 58e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private final Handler mUiThread; 59e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 60516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood private final NamedTaskExecutor mIconLoaderExecutor; 61e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Creates a new icon loader. 643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 6525f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert * @param context The QSB application context. 66e1fc4581ebab65220a82bcdb3272b4eb85453837Bjorn Bringert * @param packageName The name of the package from which the icons will be loaded. 673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Resource IDs without an explicit package will be resolved against the package 683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * of this context. 693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 70516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood public PackageIconLoader(Context context, String packageName, Handler uiThread, 71516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood NamedTaskExecutor iconLoaderExecutor) { 7225f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert mContext = context; 7325f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert mPackageName = packageName; 74e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mUiThread = uiThread; 75516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood mIconLoaderExecutor = iconLoaderExecutor; 7625f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert } 7725f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert 7825f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert private boolean ensurePackageContext() { 7925f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert if (mPackageContext == null) { 8025f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert try { 8125f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert mPackageContext = mContext.createPackageContext(mPackageName, 8225f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert Context.CONTEXT_RESTRICTED); 8325f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert } catch (PackageManager.NameNotFoundException ex) { 8425f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert // This should only happen if the app has just be uninstalled 8525f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert Log.e(TAG, "Application not found " + mPackageName); 8625f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert return false; 8725f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert } 8825f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert } 8925f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert return true; 903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 92e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood public NowOrLater<Drawable> getIcon(final String drawableId) { 933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "getIcon(" + drawableId + ")"); 943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (TextUtils.isEmpty(drawableId) || "0".equals(drawableId)) { 95e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return new Now<Drawable>(null); 963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 97e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (!ensurePackageContext()) { 98e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return new Now<Drawable>(null); 99e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 100e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood NowOrLater<Drawable> drawable; 1013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert try { 1023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // First, see if it's just an integer 1033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert int resourceId = Integer.parseInt(drawableId); 1043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // If so, find it by resource ID 105e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood Drawable icon = mPackageContext.getResources().getDrawable(resourceId); 106e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood drawable = new Now<Drawable>(icon); 1073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } catch (NumberFormatException nfe) { 1083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // It's not an integer, use it as a URI 1093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Uri uri = Uri.parse(drawableId); 110516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(uri.getScheme())) { 111e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood // load all resources synchronously, to reduce UI flickering 112e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood drawable = new Now<Drawable>(getDrawable(uri)); 113e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } else { 114e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood drawable = new IconLaterTask(uri); 115e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 1163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } catch (Resources.NotFoundException nfe) { 1173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // It was an integer, but it couldn't be found, bail out 1183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Log.w(TAG, "Icon resource not found: " + drawableId); 119e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood drawable = new Now<Drawable>(null); 1203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 121e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return drawable; 1223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public Uri getIconUri(String drawableId) { 1253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (TextUtils.isEmpty(drawableId) || "0".equals(drawableId)) { 1263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return null; 1273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 12825f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert if (!ensurePackageContext()) return null; 1293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert try { 1303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert int resourceId = Integer.parseInt(drawableId); 1312353e9c002c45c0adc8a979a49ff317cae5838b8Bjorn Bringert return Util.getResourceUri(mPackageContext, resourceId); 1323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } catch (NumberFormatException nfe) { 1333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return Uri.parse(drawableId); 1343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 1383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Gets a drawable by URI. 1393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 1403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * @return A drawable, or {@code null} if the drawable could not be loaded. 1413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 1423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private Drawable getDrawable(Uri uri) { 1433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert try { 1443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String scheme = uri.getScheme(); 1453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) { 1463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Load drawables through Resources, to get the source density information 1473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert OpenResourceIdResult r = getResourceId(uri); 1483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert try { 1493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return r.r.getDrawable(r.id); 1503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } catch (Resources.NotFoundException ex) { 1513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert throw new FileNotFoundException("Resource does not exist: " + uri); 1523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } else { 1543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Let the ContentResolver handle content and file URIs. 1553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert InputStream stream = mPackageContext.getContentResolver().openInputStream(uri); 1563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (stream == null) { 1573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert throw new FileNotFoundException("Failed to open " + uri); 1583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert try { 1603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return Drawable.createFromStream(stream, null); 1613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } finally { 1623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert try { 1633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert stream.close(); 1643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } catch (IOException ex) { 1653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Log.e(TAG, "Error closing icon stream for " + uri, ex); 1663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } catch (FileNotFoundException fnfe) { 1703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Log.w(TAG, "Icon not found: " + uri + ", " + fnfe.getMessage()); 1713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return null; 1723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 1763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * A resource identified by the {@link Resources} that contains it, and a resource id. 1773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 17825f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert private class OpenResourceIdResult { 1793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public Resources r; 1803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public int id; 1813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 1843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Resolves an android.resource URI to a {@link Resources} and a resource id. 1853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 18625f44e14e0638b84b0a3f40f3f1a663cc3e999cbBjorn Bringert private OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException { 1873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String authority = uri.getAuthority(); 1883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Resources r; 1893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (TextUtils.isEmpty(authority)) { 1903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert throw new FileNotFoundException("No authority: " + uri); 1913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } else { 1923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert try { 1933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert r = mPackageContext.getPackageManager().getResourcesForApplication(authority); 1943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } catch (NameNotFoundException ex) { 1952353e9c002c45c0adc8a979a49ff317cae5838b8Bjorn Bringert throw new FileNotFoundException("Failed to get resources: " + ex); 1963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert List<String> path = uri.getPathSegments(); 1993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (path == null) { 2003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert throw new FileNotFoundException("No path: " + uri); 2013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert int len = path.size(); 2033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert int id; 2043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (len == 1) { 2053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert try { 2063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert id = Integer.parseInt(path.get(0)); 2073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } catch (NumberFormatException e) { 2083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert throw new FileNotFoundException("Single path segment is not a resource ID: " + uri); 2093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } else if (len == 2) { 2113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert id = r.getIdentifier(path.get(1), path.get(0), authority); 2123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } else { 2133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert throw new FileNotFoundException("More than two path segments: " + uri); 2143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (id == 0) { 2163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert throw new FileNotFoundException("No resource found for: " + uri); 2173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert OpenResourceIdResult res = new OpenResourceIdResult(); 2193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert res.r = r; 2203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert res.id = id; 2213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return res; 2223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 223e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 224516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood private class IconLaterTask extends CachedLater<Drawable> implements NamedTask { 225e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private final Uri mUri; 226e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 227e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood public IconLaterTask(Uri iconUri) { 228e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mUri = iconUri; 229e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 230e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 231e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood @Override 232e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood protected void create() { 233516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood mIconLoaderExecutor.execute(this); 234e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 235e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 236e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood @Override 237e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood public void run() { 238e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood final Drawable icon = getIcon(); 239e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mUiThread.post(new Runnable(){ 240e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood public void run() { 241e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood store(icon); 242e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood }}); 243e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 244e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 245516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood @Override 246516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood public String getName() { 247516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood return mPackageName; 248516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood } 249516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood 250e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private Drawable getIcon() { 251e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood try { 252e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return getDrawable(mUri); 253e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } catch (Throwable t) { 254e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood // we're making a call into another package, which could throw any exception. 255e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood // Make sure it doesn't crash QSB 256e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood Log.e(TAG, "Failed to load icon " + mUri, t); 257e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return null; 258e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 259e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 260e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 2613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert} 262