1e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill/* 2e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * Copyright (C) 2013 The Android Open Source Project 3e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * 4e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * Licensed under the Apache License, Version 2.0 (the "License"); 5e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * you may not use this file except in compliance with the License. 6e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * You may obtain a copy of the License at 7e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * 8e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * http://www.apache.org/licenses/LICENSE-2.0 9e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * 10e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * Unless required by applicable law or agreed to in writing, software 11e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * distributed under the License is distributed on an "AS IS" BASIS, 12e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * See the License for the specific language governing permissions and 14e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * limitations under the License. 15e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill */ 16e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 17e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillpackage com.android.settings.location; 18e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 19e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport android.content.Context; 20e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport android.content.Intent; 21421dccd5dd8cdec03bbc704b142f3ca2396f7e40Tom O'Neillimport android.content.pm.ApplicationInfo; 22e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport android.content.pm.PackageManager; 23e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport android.content.pm.ResolveInfo; 24e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport android.content.pm.ServiceInfo; 25e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport android.content.res.Resources; 26e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport android.content.res.TypedArray; 27e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport android.content.res.XmlResourceParser; 28e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport android.graphics.drawable.Drawable; 29e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport android.location.SettingInjectorService; 30e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport android.os.Bundle; 31e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport android.os.Handler; 32e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport android.os.Message; 33e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport android.os.Messenger; 341810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neillimport android.os.SystemClock; 35e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport android.preference.Preference; 36e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport android.util.AttributeSet; 37e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport android.util.Log; 38e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport android.util.Xml; 39e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neillimport com.android.settings.R; 40e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport org.xmlpull.v1.XmlPullParser; 41e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport org.xmlpull.v1.XmlPullParserException; 42e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 43e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport java.io.IOException; 44e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport java.util.ArrayList; 45e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neillimport java.util.HashSet; 46e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neillimport java.util.Iterator; 47e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillimport java.util.List; 48e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neillimport java.util.Set; 49e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 50e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill/** 51e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * Adds the preferences specified by the {@link InjectedSetting} objects to a preference group. 52e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * 53e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * Duplicates some code from {@link android.content.pm.RegisteredServicesCache}. We do not use that 54e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * class directly because it is not a good match for our use case: we do not need the caching, and 55e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * so do not want the additional resource hit at app install/upgrade time; and we would have to 56e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * suppress the tie-breaking between multiple services reporting settings with the same name. 57e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * Code-sharing would require extracting {@link 58e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * android.content.pm.RegisteredServicesCache#parseServiceAttributes(android.content.res.Resources, 59e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * String, android.util.AttributeSet)} into an interface, which didn't seem worth it. 60e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill */ 61e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neillclass SettingsInjector { 62e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill static final String TAG = "SettingsInjector"; 63e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 64f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill /** 65f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill * If reading the status of a setting takes longer than this, we go ahead and start reading 66f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill * the next setting. 67f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill */ 6825518c3b45827537b2b2c2b35fdc86bc8bd60502Lifu Tang private static final long INJECTED_STATUS_UPDATE_TIMEOUT_MILLIS = 1000; 6925518c3b45827537b2b2c2b35fdc86bc8bd60502Lifu Tang 70e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill /** 71e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill * {@link Message#what} value for starting to load status values 72e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill * in case we aren't already in the process of loading them. 73e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill */ 74e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill private static final int WHAT_RELOAD = 1; 75e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill 76e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill /** 77e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill * {@link Message#what} value sent after receiving a status message. 78e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill */ 79e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill private static final int WHAT_RECEIVED_STATUS = 2; 80e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill 81e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill /** 82e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill * {@link Message#what} value sent after the timeout waiting for a status message. 83e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill */ 84e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill private static final int WHAT_TIMEOUT = 3; 85e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill 86e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill private final Context mContext; 87e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill 88e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill /** 89e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill * The settings that were injected 90e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill */ 91e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill private final Set<Setting> mSettings; 92e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill 93e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill private final Handler mHandler; 9432e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang 9532e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang public SettingsInjector(Context context) { 9632e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang mContext = context; 97e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill mSettings = new HashSet<Setting>(); 98e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill mHandler = new StatusLoadingHandler(); 9932e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang } 10032e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang 101e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill /** 102e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * Returns a list with one {@link InjectedSetting} object for each {@link android.app.Service} 1031810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill * that responds to {@link SettingInjectorService#ACTION_SERVICE_INTENT} and provides the 1041810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill * expected setting metadata. 105e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * 106e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * Duplicates some code from {@link android.content.pm.RegisteredServicesCache}. 107e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * 108e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * TODO: unit test 109e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill */ 11032e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang private List<InjectedSetting> getSettings() { 11132e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang PackageManager pm = mContext.getPackageManager(); 1121810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill Intent intent = new Intent(SettingInjectorService.ACTION_SERVICE_INTENT); 113e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 114e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill List<ResolveInfo> resolveInfos = 1151810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill pm.queryIntentServices(intent, PackageManager.GET_META_DATA); 116e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill if (Log.isLoggable(TAG, Log.DEBUG)) { 117e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill Log.d(TAG, "Found services: " + resolveInfos); 118e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 119e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill List<InjectedSetting> settings = new ArrayList<InjectedSetting>(resolveInfos.size()); 1201810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill for (ResolveInfo resolveInfo : resolveInfos) { 121e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill try { 1221810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill InjectedSetting setting = parseServiceInfo(resolveInfo, pm); 1231810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill if (setting == null) { 1241810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill Log.w(TAG, "Unable to load service info " + resolveInfo); 125e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } else { 1261810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill settings.add(setting); 127e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 128e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } catch (XmlPullParserException e) { 1291810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill Log.w(TAG, "Unable to load service info " + resolveInfo, e); 130e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } catch (IOException e) { 1311810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill Log.w(TAG, "Unable to load service info " + resolveInfo, e); 132e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 133e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 1341810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill if (Log.isLoggable(TAG, Log.DEBUG)) { 1351810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill Log.d(TAG, "Loaded settings: " + settings); 1361810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill } 137e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 138e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill return settings; 139e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 140e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 141e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill /** 142421dccd5dd8cdec03bbc704b142f3ca2396f7e40Tom O'Neill * Returns the settings parsed from the attributes of the 143421dccd5dd8cdec03bbc704b142f3ca2396f7e40Tom O'Neill * {@link SettingInjectorService#META_DATA_NAME} tag, or null. 144e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * 145e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * Duplicates some code from {@link android.content.pm.RegisteredServicesCache}. 146e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill */ 147e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill private static InjectedSetting parseServiceInfo(ResolveInfo service, PackageManager pm) 148e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill throws XmlPullParserException, IOException { 149e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 150e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill ServiceInfo si = service.serviceInfo; 151421dccd5dd8cdec03bbc704b142f3ca2396f7e40Tom O'Neill ApplicationInfo ai = si.applicationInfo; 152421dccd5dd8cdec03bbc704b142f3ca2396f7e40Tom O'Neill 153421dccd5dd8cdec03bbc704b142f3ca2396f7e40Tom O'Neill if ((ai.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { 154421dccd5dd8cdec03bbc704b142f3ca2396f7e40Tom O'Neill if (Log.isLoggable(TAG, Log.WARN)) { 155421dccd5dd8cdec03bbc704b142f3ca2396f7e40Tom O'Neill Log.w(TAG, "Ignoring attempt to inject setting from app not in system image: " 156421dccd5dd8cdec03bbc704b142f3ca2396f7e40Tom O'Neill + service); 157421dccd5dd8cdec03bbc704b142f3ca2396f7e40Tom O'Neill return null; 158421dccd5dd8cdec03bbc704b142f3ca2396f7e40Tom O'Neill } 159421dccd5dd8cdec03bbc704b142f3ca2396f7e40Tom O'Neill } 160e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 161e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill XmlResourceParser parser = null; 162e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill try { 1631810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill parser = si.loadXmlMetaData(pm, SettingInjectorService.META_DATA_NAME); 164e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill if (parser == null) { 1651810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill throw new XmlPullParserException("No " + SettingInjectorService.META_DATA_NAME 166e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill + " meta-data for " + service + ": " + si); 167e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 168e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 169e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill AttributeSet attrs = Xml.asAttributeSet(parser); 170e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 171e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill int type; 172e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 173e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill && type != XmlPullParser.START_TAG) { 174e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 175e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 176e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill String nodeName = parser.getName(); 1771810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill if (!SettingInjectorService.ATTRIBUTES_NAME.equals(nodeName)) { 178e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill throw new XmlPullParserException("Meta-data does not start with " 1791810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill + SettingInjectorService.ATTRIBUTES_NAME + " tag"); 180e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 181e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 182421dccd5dd8cdec03bbc704b142f3ca2396f7e40Tom O'Neill Resources res = pm.getResourcesForApplication(ai); 183e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill return parseAttributes(si.packageName, si.name, res, attrs); 184e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } catch (PackageManager.NameNotFoundException e) { 185e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill throw new XmlPullParserException( 186e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill "Unable to load resources for package " + si.packageName); 187e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } finally { 188e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill if (parser != null) { 189e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill parser.close(); 190e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 191e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 192e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 193e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 194e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill /** 195e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill * Returns an immutable representation of the static attributes for the setting, or null. 196e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill */ 197e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill private static InjectedSetting parseAttributes( 198e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill String packageName, String className, Resources res, AttributeSet attrs) { 199e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 2001810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill TypedArray sa = res.obtainAttributes(attrs, android.R.styleable.SettingInjectorService); 201e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill try { 202e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill // Note that to help guard against malicious string injection, we do not allow dynamic 203e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill // specification of the label (setting title) 204421dccd5dd8cdec03bbc704b142f3ca2396f7e40Tom O'Neill final String title = sa.getString(android.R.styleable.SettingInjectorService_title); 205421dccd5dd8cdec03bbc704b142f3ca2396f7e40Tom O'Neill final int iconId = 206421dccd5dd8cdec03bbc704b142f3ca2396f7e40Tom O'Neill sa.getResourceId(android.R.styleable.SettingInjectorService_icon, 0); 207e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill final String settingsActivity = 2081810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill sa.getString(android.R.styleable.SettingInjectorService_settingsActivity); 209e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill if (Log.isLoggable(TAG, Log.DEBUG)) { 210421dccd5dd8cdec03bbc704b142f3ca2396f7e40Tom O'Neill Log.d(TAG, "parsed title: " + title + ", iconId: " + iconId 211e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill + ", settingsActivity: " + settingsActivity); 212e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 213e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill return InjectedSetting.newInstance(packageName, className, 214421dccd5dd8cdec03bbc704b142f3ca2396f7e40Tom O'Neill title, iconId, settingsActivity); 215e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } finally { 216e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill sa.recycle(); 217e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 218e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 219e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 220e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill /** 22125518c3b45827537b2b2c2b35fdc86bc8bd60502Lifu Tang * Gets a list of preferences that other apps have injected. 222e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill */ 22332e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang public List<Preference> getInjectedSettings() { 22432e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang Iterable<InjectedSetting> settings = getSettings(); 22525518c3b45827537b2b2c2b35fdc86bc8bd60502Lifu Tang ArrayList<Preference> prefs = new ArrayList<Preference>(); 226e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill for (InjectedSetting setting : settings) { 22732e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang Preference pref = addServiceSetting(prefs, setting); 228e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill mSettings.add(new Setting(setting, pref)); 22925518c3b45827537b2b2c2b35fdc86bc8bd60502Lifu Tang } 230e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 231e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill reloadStatusMessages(); 23225518c3b45827537b2b2c2b35fdc86bc8bd60502Lifu Tang 23325518c3b45827537b2b2c2b35fdc86bc8bd60502Lifu Tang return prefs; 234e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 235e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 236e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill /** 23732e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang * Reloads the status messages for all the preference items. 23832e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang */ 23932e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang public void reloadStatusMessages() { 240e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill if (Log.isLoggable(TAG, Log.DEBUG)) { 241e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill Log.d(TAG, "reloadingStatusMessages: " + mSettings); 24232e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang } 243e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill mHandler.sendMessage(mHandler.obtainMessage(WHAT_RELOAD)); 24432e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang } 24532e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang 24632e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang /** 247e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill * Adds an injected setting to the root with status "Loading...". 248e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill */ 24932e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang private Preference addServiceSetting(List<Preference> prefs, InjectedSetting info) { 25032e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang Preference pref = new Preference(mContext); 25108a4c33a409f7cc693527de138179f80bf07be9cLifu Tang pref.setTitle(info.title); 25208a4c33a409f7cc693527de138179f80bf07be9cLifu Tang pref.setSummary(R.string.location_loading_injected_setting); 25332e016b5fae1f4caf673ff1f062869dce0e94757Lifu Tang PackageManager pm = mContext.getPackageManager(); 254e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill Drawable icon = pm.getDrawable(info.packageName, info.iconId, null); 25508a4c33a409f7cc693527de138179f80bf07be9cLifu Tang pref.setIcon(icon); 256e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 257e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill Intent settingIntent = new Intent(); 258e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill settingIntent.setClassName(info.packageName, info.settingsActivity); 25908a4c33a409f7cc693527de138179f80bf07be9cLifu Tang pref.setIntent(settingIntent); 260e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 26108a4c33a409f7cc693527de138179f80bf07be9cLifu Tang prefs.add(pref); 26208a4c33a409f7cc693527de138179f80bf07be9cLifu Tang return pref; 263e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 264e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill 265e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill /** 266e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill * Loads the setting status values one at a time. Each load starts a subclass of {@link 267e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill * SettingInjectorService}, so to reduce memory pressure we don't want to load too many at 268e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill * once. 269e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill */ 270e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill private final class StatusLoadingHandler extends Handler { 271e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill 272e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill /** 273f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill * Settings whose status values need to be loaded. A set is used to prevent redundant loads. 274e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill */ 275f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill private Set<Setting> mSettingsToLoad = new HashSet<Setting>(); 276e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill 277e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill /** 278f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill * Settings that are being loaded now and haven't timed out. In practice this should have 279f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill * zero or one elements. 280e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill */ 281f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill private Set<Setting> mSettingsBeingLoaded = new HashSet<Setting>(); 282f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill 283f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill /** 284f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill * Settings that are being loaded but have timed out. If only one setting has timed out, we 285f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill * will go ahead and start loading the next setting so that one slow load won't delay the 286f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill * load of the other settings. 287f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill */ 288f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill private Set<Setting> mTimedOutSettings = new HashSet<Setting>(); 289f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill 290f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill private boolean mReloadRequested; 291e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill 292e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill @Override 293e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill public void handleMessage(Message msg) { 294e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill if (Log.isLoggable(TAG, Log.DEBUG)) { 295f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill Log.d(TAG, "handleMessage start: " + msg + ", " + this); 296e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill } 297e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill 298f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill // Update state in response to message 299e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill switch (msg.what) { 300e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill case WHAT_RELOAD: 301f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill mReloadRequested = true; 302f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill break; 303f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill case WHAT_RECEIVED_STATUS: 304f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill final Setting receivedSetting = (Setting) msg.obj; 3051810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill receivedSetting.maybeLogElapsedTime(); 306f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill mSettingsBeingLoaded.remove(receivedSetting); 307f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill mTimedOutSettings.remove(receivedSetting); 308f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill removeMessages(WHAT_TIMEOUT, receivedSetting); 309e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill break; 310e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill case WHAT_TIMEOUT: 311f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill final Setting timedOutSetting = (Setting) msg.obj; 312f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill mSettingsBeingLoaded.remove(timedOutSetting); 313f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill mTimedOutSettings.add(timedOutSetting); 314e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill if (Log.isLoggable(TAG, Log.WARN)) { 3157f91d8628320f8669efb2ba660c7ca1dcd2da881Tom O'Neill Log.w(TAG, "Timed out after " + timedOutSetting.getElapsedTime() 3167f91d8628320f8669efb2ba660c7ca1dcd2da881Tom O'Neill + " millis trying to get status for: " + timedOutSetting); 317e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill } 318e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill break; 319e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill default: 320f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill Log.wtf(TAG, "Unexpected what: " + msg); 321f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill } 322f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill 323007994279c6d9e41fe35a6804eb4ca753d139969Lifu Tang // Decide whether to load additional settings based on the new state. Start by seeing 324f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill // if we have headroom to load another setting. 325f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill if (mSettingsBeingLoaded.size() > 0 || mTimedOutSettings.size() > 1) { 326f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill // Don't load any more settings until one of the pending settings has completed. 327f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill // To reduce memory pressure, we want to be loading at most one setting (plus at 328f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill // most one timed-out setting) at a time. This means we'll be responsible for 329f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill // bringing in at most two services. 330f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill if (Log.isLoggable(TAG, Log.VERBOSE)) { 331f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill Log.v(TAG, "too many services already live for " + msg + ", " + this); 332f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill } 333f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill return; 334f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill } 335f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill 336f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill if (mReloadRequested && mSettingsToLoad.isEmpty() && mSettingsBeingLoaded.isEmpty() 337f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill && mTimedOutSettings.isEmpty()) { 338f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill if (Log.isLoggable(TAG, Log.VERBOSE)) { 339f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill Log.v(TAG, "reloading because idle and reload requesteed " + msg + ", " + this); 340f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill } 341f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill // Reload requested, so must reload all settings 342f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill mSettingsToLoad.addAll(mSettings); 343f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill mReloadRequested = false; 344e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill } 345e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill 346e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill // Remove the next setting to load from the queue, if any 347e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill Iterator<Setting> iter = mSettingsToLoad.iterator(); 348e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill if (!iter.hasNext()) { 349f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill if (Log.isLoggable(TAG, Log.VERBOSE)) { 350f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill Log.v(TAG, "nothing left to do for " + msg + ", " + this); 351f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill } 352e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill return; 353e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill } 354e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill Setting setting = iter.next(); 355e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill iter.remove(); 356e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill 357e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill // Request the status value 3581810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill setting.startService(); 359f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill mSettingsBeingLoaded.add(setting); 360e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill 361e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill // Ensure that if receiving the status value takes too long, we start loading the 362e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill // next value anyway 363e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill Message timeoutMsg = obtainMessage(WHAT_TIMEOUT, setting); 364e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill sendMessageDelayed(timeoutMsg, INJECTED_STATUS_UPDATE_TIMEOUT_MILLIS); 365e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill 366e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill if (Log.isLoggable(TAG, Log.DEBUG)) { 367f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill Log.d(TAG, "handleMessage end " + msg + ", " + this 368f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill + ", started loading " + setting); 369e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill } 370e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill } 371f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill 372f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill @Override 373f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill public String toString() { 374f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill return "StatusLoadingHandler{" + 375f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill "mSettingsToLoad=" + mSettingsToLoad + 376f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill ", mSettingsBeingLoaded=" + mSettingsBeingLoaded + 377f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill ", mTimedOutSettings=" + mTimedOutSettings + 378f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill ", mReloadRequested=" + mReloadRequested + 379f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill '}'; 380f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill } 381e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill } 382e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill 383e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill /** 384e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill * Represents an injected setting and the corresponding preference. 385e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill */ 386e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill private final class Setting { 387e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill 388e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill public final InjectedSetting setting; 389e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill public final Preference preference; 3901810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill public long startMillis; 391e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill 392e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill private Setting(InjectedSetting setting, Preference preference) { 393e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill this.setting = setting; 394e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill this.preference = preference; 395e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill } 396e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill 397e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill @Override 398e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill public String toString() { 399e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill return "Setting{" + 400e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill "setting=" + setting + 401e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill ", preference=" + preference + 402e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill '}'; 403e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill } 404e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill 405e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill /** 406f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill * Returns true if they both have the same {@link #setting} value. Ignores mutable 4071810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill * {@link #preference} and {@link #startMillis} so that it's safe to use in sets. 408f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill */ 409f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill @Override 410f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill public boolean equals(Object o) { 411f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill return this == o || o instanceof Setting && setting.equals(((Setting) o).setting); 412f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill } 413f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill 414f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill @Override 415f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill public int hashCode() { 416f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill return setting.hashCode(); 417f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill } 418f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill 419f06dc3216318672d5a30d58c0cfcb4142dbab2c2Tom O'Neill /** 4201810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill * Starts the service to fetch for the current status for the setting, and updates the 4211810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill * preference when the service replies. 422e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill */ 4231810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill public void startService() { 424e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill Handler handler = new Handler() { 425e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill @Override 426e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill public void handleMessage(Message msg) { 427e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill Bundle bundle = msg.getData(); 428b578ac4f94542eb7a2988e51045b931305871b97Tom O'Neill String summary = bundle.getString(SettingInjectorService.SUMMARY_KEY); 429e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill boolean enabled = bundle.getBoolean(SettingInjectorService.ENABLED_KEY, true); 430e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill if (Log.isLoggable(TAG, Log.DEBUG)) { 431e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill Log.d(TAG, setting + ": received " + msg + ", bundle: " + bundle); 432e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill } 433b578ac4f94542eb7a2988e51045b931305871b97Tom O'Neill preference.setSummary(summary); 434e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill preference.setEnabled(enabled); 435e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill mHandler.sendMessage( 436e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill mHandler.obtainMessage(WHAT_RECEIVED_STATUS, Setting.this)); 43725518c3b45827537b2b2c2b35fdc86bc8bd60502Lifu Tang } 438e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill }; 439e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill Messenger messenger = new Messenger(handler); 4401810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill 4411810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill Intent intent = setting.getServiceIntent(); 4421810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill intent.putExtra(SettingInjectorService.MESSENGER_KEY, messenger); 4431810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill 444e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill if (Log.isLoggable(TAG, Log.DEBUG)) { 4451810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill Log.d(TAG, setting + ": sending update intent: " + intent 446e17ce5fb73efe8046f9d806a6fbb9a5abb5b0e87Tom O'Neill + ", handler: " + handler); 4471810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill startMillis = SystemClock.elapsedRealtime(); 4481810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill } else { 4491810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill startMillis = 0; 4501810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill } 4517f91d8628320f8669efb2ba660c7ca1dcd2da881Tom O'Neill 4527f91d8628320f8669efb2ba660c7ca1dcd2da881Tom O'Neill // Start the service, making sure that this is attributed to the current user rather 4537f91d8628320f8669efb2ba660c7ca1dcd2da881Tom O'Neill // than the system user. 4547f91d8628320f8669efb2ba660c7ca1dcd2da881Tom O'Neill mContext.startServiceAsUser(intent, android.os.Process.myUserHandle()); 4557f91d8628320f8669efb2ba660c7ca1dcd2da881Tom O'Neill } 4567f91d8628320f8669efb2ba660c7ca1dcd2da881Tom O'Neill 4577f91d8628320f8669efb2ba660c7ca1dcd2da881Tom O'Neill public long getElapsedTime() { 4587f91d8628320f8669efb2ba660c7ca1dcd2da881Tom O'Neill long end = SystemClock.elapsedRealtime(); 4597f91d8628320f8669efb2ba660c7ca1dcd2da881Tom O'Neill return end - startMillis; 4601810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill } 4611810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill 4621810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill public void maybeLogElapsedTime() { 4631810a88e5fcb81dfa6ebac4f155e8ca63789d3d4Tom O'Neill if (Log.isLoggable(TAG, Log.DEBUG) && startMillis != 0) { 4647f91d8628320f8669efb2ba660c7ca1dcd2da881Tom O'Neill long elapsed = getElapsedTime(); 4657f91d8628320f8669efb2ba660c7ca1dcd2da881Tom O'Neill Log.d(TAG, this + " update took " + elapsed + " millis"); 466e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 467e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 468e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill } 469e2921c9566e34fd95b864cca247ff71cf9b30752Tom O'Neill} 470