1dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson/* 2dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * Copyright (C) 2014 The Android Open Source Project 3dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * 4dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * Licensed under the Apache License, Version 2.0 (the "License"); 5dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * you may not use this file except in compliance with the License. 6dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * You may obtain a copy of the License at 7dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * 8dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * http://www.apache.org/licenses/LICENSE-2.0 9dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * 10dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * Unless required by applicable law or agreed to in writing, software 11dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * distributed under the License is distributed on an "AS IS" BASIS, 12dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * See the License for the specific language governing permissions and 14dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * limitations under the License 15dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson */ 16dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson 17dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidsonpackage android.net; 18dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson 19ac7285dc1e13f30d59dad30fe2ad1116e5f676cbJeff Davidsonimport android.Manifest; 20dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidsonimport android.Manifest.permission; 21b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidsonimport android.annotation.Nullable; 22dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidsonimport android.app.AppOpsManager; 23dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidsonimport android.content.Context; 24dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidsonimport android.content.Intent; 25dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidsonimport android.content.pm.ActivityInfo; 26dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidsonimport android.content.pm.PackageManager; 27dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidsonimport android.content.pm.ResolveInfo; 28ac7285dc1e13f30d59dad30fe2ad1116e5f676cbJeff Davidsonimport android.os.UserHandle; 29dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidsonimport android.provider.Settings; 30dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidsonimport android.text.TextUtils; 316a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.util.Log; 32dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson 33dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidsonimport java.util.ArrayList; 34dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidsonimport java.util.Collection; 35dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidsonimport java.util.List; 36dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson 37dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson/** 38dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * Internal class for managing the primary network scorer application. 39dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * 40c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson * TODO: Rename this to something more generic. 41c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson * 42dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * @hide 43dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson */ 446a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonpublic final class NetworkScorerAppManager { 456a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson private static final String TAG = "NetworkScorerAppManager"; 46dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson 47dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson private static final Intent SCORE_INTENT = 48dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson new Intent(NetworkScoreManager.ACTION_SCORE_NETWORKS); 49dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson 50dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson /** This class cannot be instantiated. */ 516a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson private NetworkScorerAppManager() {} 52dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson 53c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson public static class NetworkScorerAppData { 54c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson /** Package name of this scorer app. */ 55c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson public final String mPackageName; 56c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson 57c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson /** Name of this scorer app for display. */ 58c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson public final CharSequence mScorerName; 59c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson 60b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson /** 61b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson * Optional class name of a configuration activity. Null if none is set. 62b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson * 63b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson * @see NetworkScoreManager#ACTION_CUSTOM_ENABLE 64b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson */ 65b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson public final String mConfigurationActivityClassName; 66b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson 67b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson public NetworkScorerAppData(String packageName, CharSequence scorerName, 68b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson @Nullable String configurationActivityClassName) { 69c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson mScorerName = scorerName; 70c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson mPackageName = packageName; 71b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson mConfigurationActivityClassName = configurationActivityClassName; 72c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson } 73c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson } 74c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson 75dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson /** 76c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson * Returns the list of available scorer apps. 77dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * 78dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * <p>A network scorer is any application which: 79dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * <ul> 80dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * <li>Declares the {@link android.Manifest.permission#SCORE_NETWORKS} permission. 81dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * <li>Includes a receiver for {@link NetworkScoreManager#ACTION_SCORE_NETWORKS} guarded by the 82161977998feebf0a855ea56558464470877040cfJeff Davidson * {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission. 83dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * </ul> 84dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * 85dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * @return the list of scorers, or the empty list if there are no valid scorers. 86dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson */ 87c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson public static Collection<NetworkScorerAppData> getAllValidScorers(Context context) { 88c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson List<NetworkScorerAppData> scorers = new ArrayList<>(); 89dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson 90dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson PackageManager pm = context.getPackageManager(); 91ac7285dc1e13f30d59dad30fe2ad1116e5f676cbJeff Davidson // Only apps installed under the primary user of the device can be scorers. 92ac7285dc1e13f30d59dad30fe2ad1116e5f676cbJeff Davidson List<ResolveInfo> receivers = 93ac7285dc1e13f30d59dad30fe2ad1116e5f676cbJeff Davidson pm.queryBroadcastReceivers(SCORE_INTENT, 0 /* flags */, UserHandle.USER_OWNER); 94dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson for (ResolveInfo receiver : receivers) { 95dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson // This field is a misnomer, see android.content.pm.ResolveInfo#activityInfo 96dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson final ActivityInfo receiverInfo = receiver.activityInfo; 97dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson if (receiverInfo == null) { 98dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson // Should never happen with queryBroadcastReceivers, but invalid nonetheless. 99dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson continue; 100dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson } 101161977998feebf0a855ea56558464470877040cfJeff Davidson if (!permission.BROADCAST_NETWORK_PRIVILEGED.equals(receiverInfo.permission)) { 102161977998feebf0a855ea56558464470877040cfJeff Davidson // Receiver doesn't require the BROADCAST_NETWORK_PRIVILEGED permission, which means 103dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson // anyone could trigger network scoring and flood the framework with score requests. 104dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson continue; 105dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson } 106dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson if (pm.checkPermission(permission.SCORE_NETWORKS, receiverInfo.packageName) != 107dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson PackageManager.PERMISSION_GRANTED) { 108dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson // Application doesn't hold the SCORE_NETWORKS permission, so the user never 109dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson // approved it as a network scorer. 110dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson continue; 111dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson } 112b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson 113b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson // Optionally, this package may specify a configuration activity. 114b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson String configurationActivityClassName = null; 115b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson Intent intent = new Intent(NetworkScoreManager.ACTION_CUSTOM_ENABLE); 116b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson intent.setPackage(receiverInfo.packageName); 117b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson List<ResolveInfo> configActivities = pm.queryIntentActivities(intent, 0 /* flags */); 118b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson if (!configActivities.isEmpty()) { 119b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson ActivityInfo activityInfo = configActivities.get(0).activityInfo; 120b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson if (activityInfo != null) { 121b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson configurationActivityClassName = activityInfo.name; 122b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson } 123b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson } 124b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson 125c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson // NOTE: loadLabel will attempt to load the receiver's label and fall back to the app 126c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson // label if none is present. 127b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson scorers.add(new NetworkScorerAppData(receiverInfo.packageName, 128b6646a8987a8ce6abd34cc05d9ca0193a6d7bea9Jeff Davidson receiverInfo.loadLabel(pm), configurationActivityClassName)); 129dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson } 130dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson 131dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson return scorers; 132dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson } 133dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson 134dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson /** 135c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson * Get the application to use for scoring networks. 136dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * 137c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson * @return the scorer app info or null if scoring is disabled (including if no scorer was ever 138dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * selected) or if the previously-set scorer is no longer a valid scorer app (e.g. because 139dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * it was disabled or uninstalled). 140dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson */ 141c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson public static NetworkScorerAppData getActiveScorer(Context context) { 142dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson String scorerPackage = Settings.Global.getString(context.getContentResolver(), 143c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson Settings.Global.NETWORK_SCORER_APP); 144c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson return getScorer(context, scorerPackage); 145dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson } 146dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson 147dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson /** 148dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * Set the specified package as the default scorer application. 149dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * 150c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson * <p>The caller must have permission to write to {@link android.provider.Settings.Global}. 151dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * 152dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * @param context the context of the calling application 153dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * @param packageName the packageName of the new scorer to use. If null, scoring will be 154dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson * disabled. Otherwise, the scorer will only be set if it is a valid scorer application. 1556a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * @return true if the scorer was changed, or false if the package is not a valid scorer. 156dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson */ 1576a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson public static boolean setActiveScorer(Context context, String packageName) { 158dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson String oldPackageName = Settings.Global.getString(context.getContentResolver(), 159dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson Settings.Global.NETWORK_SCORER_APP); 160dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson if (TextUtils.equals(oldPackageName, packageName)) { 161dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson // No change. 1626a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson return true; 163dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson } 164dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson 1656a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson Log.i(TAG, "Changing network scorer from " + oldPackageName + " to " + packageName); 1666a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 167dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson if (packageName == null) { 168c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson Settings.Global.putString(context.getContentResolver(), 169c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson Settings.Global.NETWORK_SCORER_APP, null); 1706a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson return true; 171dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson } else { 172dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson // We only make the change if the new package is valid. 173c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson if (getScorer(context, packageName) != null) { 174dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson Settings.Global.putString(context.getContentResolver(), 175dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson Settings.Global.NETWORK_SCORER_APP, packageName); 1766a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson return true; 1776a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } else { 1786a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson Log.w(TAG, "Requested network scorer is not valid: " + packageName); 1796a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson return false; 180dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson } 181dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson } 182dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson } 183dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson 184dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson /** Determine whether the application with the given UID is the enabled scorer. */ 1856a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson public static boolean isCallerActiveScorer(Context context, int callingUid) { 186c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson NetworkScorerAppData defaultApp = getActiveScorer(context); 187dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson if (defaultApp == null) { 188dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson return false; 189dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson } 190dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson AppOpsManager appOpsMgr = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 191dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson try { 192c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson appOpsMgr.checkPackage(callingUid, defaultApp.mPackageName); 193dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson } catch (SecurityException e) { 194dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson return false; 195dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson } 196ac7285dc1e13f30d59dad30fe2ad1116e5f676cbJeff Davidson 197ac7285dc1e13f30d59dad30fe2ad1116e5f676cbJeff Davidson // To be extra safe, ensure the caller holds the SCORE_NETWORKS permission. It always 198ac7285dc1e13f30d59dad30fe2ad1116e5f676cbJeff Davidson // should, since it couldn't become the active scorer otherwise, but this can't hurt. 199ac7285dc1e13f30d59dad30fe2ad1116e5f676cbJeff Davidson return context.checkCallingPermission(Manifest.permission.SCORE_NETWORKS) == 200ac7285dc1e13f30d59dad30fe2ad1116e5f676cbJeff Davidson PackageManager.PERMISSION_GRANTED; 201dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson } 202dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson 203c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson /** Returns the {@link NetworkScorerAppData} for the given app, or null if it's not a scorer. */ 204c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson public static NetworkScorerAppData getScorer(Context context, String packageName) { 205c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson if (TextUtils.isEmpty(packageName)) { 206c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson return null; 207c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson } 208c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson Collection<NetworkScorerAppData> applications = getAllValidScorers(context); 209c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson for (NetworkScorerAppData app : applications) { 210c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson if (packageName.equals(app.mPackageName)) { 211c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson return app; 212c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson } 213c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson } 214c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson return null; 215dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson } 216dd6fd1e62b1792d1f96824b2fefb16d894b43197Jeff Davidson} 217