Loading api/current.txt +2 −1 Original line number Diff line number Diff line Loading @@ -22823,9 +22823,10 @@ package android.location { ctor public SettingInjectorService(java.lang.String); method public final android.os.IBinder onBind(android.content.Intent); method protected abstract boolean onGetEnabled(); method protected abstract deprecated java.lang.String onGetSummary(); method protected abstract java.lang.String onGetSummary(); method public final void onStart(android.content.Intent, int); method public final int onStartCommand(android.content.Intent, int, int); method public static final void refreshSettings(android.content.Context); field public static final java.lang.String ACTION_INJECTED_SETTING_CHANGED = "android.location.InjectedSettingChanged"; field public static final java.lang.String ACTION_SERVICE_INTENT = "android.location.SettingInjectorService"; field public static final java.lang.String ATTRIBUTES_NAME = "injected-location-setting"; location/java/android/location/SettingInjectorService.java +44 −23 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.location; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.IBinder; Loading @@ -26,7 +27,7 @@ import android.os.RemoteException; import android.util.Log; /** * Dynamically specifies the enabled status of a preference injected into * Dynamically specifies the summary (subtitle) and enabled status of a preference injected into * the list of app settings displayed by the system settings app * <p/> * For use only by apps that are included in the system image, for preferences that affect multiple Loading Loading @@ -71,12 +72,13 @@ import android.util.Log; * </ul> * * To ensure a good user experience, your {@link android.app.Application#onCreate()}, * and {@link #onGetEnabled()} methods must all be fast. If either is slow, * it can delay the display of settings values for other apps as well. Note further that these * methods are called on your app's UI thread. * {@link #onGetSummary()}, and {@link #onGetEnabled()} methods must all be fast. If any are slow, * it can delay the display of settings values for other apps as well. Note further that all are * called on your app's UI thread. * <p/> * For compactness, only one copy of a given setting should be injected. If each account has a * distinct value for the setting, then only {@code settingsActivity} should display the value for * distinct value for the setting, then the {@link #onGetSummary()} value should represent a summary * of the state across all of the accounts and {@code settingsActivity} should display the value for * each account. */ public abstract class SettingInjectorService extends Service { Loading Loading @@ -107,6 +109,14 @@ public abstract class SettingInjectorService extends Service { public static final String ACTION_INJECTED_SETTING_CHANGED = "android.location.InjectedSettingChanged"; /** * Name of the bundle key for the string specifying the summary for the setting (e.g., "ON" or * "OFF"). * * @hide */ public static final String SUMMARY_KEY = "summary"; /** * Name of the bundle key for the string specifying whether the setting is currently enabled. * Loading Loading @@ -150,36 +160,41 @@ public abstract class SettingInjectorService extends Service { } private void onHandleIntent(Intent intent) { boolean enabled; String summary = null; boolean enabled = false; try { summary = onGetSummary(); enabled = onGetEnabled(); } catch (RuntimeException e) { // Exception. Send status anyway, so that settings injector can immediately start // loading the status of the next setting. sendStatus(intent, true); throw e; } finally { // If exception happens, send status anyway, so that settings injector can immediately // start loading the status of the next setting. But leave the exception uncaught to // crash the injector service itself. sendStatus(intent, summary, enabled); } sendStatus(intent, enabled); } /** * Send the enabled values back to the caller via the messenger encoded in the * intent. */ private void sendStatus(Intent intent, boolean enabled) { private void sendStatus(Intent intent, String summary, boolean enabled) { Messenger messenger = intent.getParcelableExtra(MESSENGER_KEY); // Bail out to avoid crashing GmsCore with incoming malicious Intent. if (messenger == null) { return; } Message message = Message.obtain(); Bundle bundle = new Bundle(); bundle.putString(SUMMARY_KEY, summary); bundle.putBoolean(ENABLED_KEY, enabled); message.setData(bundle); if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, mName + ": received " + intent Log.d(TAG, mName + ": received " + intent + ", summary=" + summary + ", enabled=" + enabled + ", sending message: " + message); } Messenger messenger = intent.getParcelableExtra(MESSENGER_KEY); try { messenger.send(message); } catch (RemoteException e) { Loading @@ -188,14 +203,12 @@ public abstract class SettingInjectorService extends Service { } /** * This method is no longer called, because status values are no longer shown for any injected * setting. * * @return ignored * Returns the {@link android.preference.Preference#getSummary()} value (allowed to be null or * empty). Should not perform unpredictably-long operations such as network access--see the * running-time comments in the class-level javadoc. * * @deprecated not called any more * @return the {@link android.preference.Preference#getSummary()} value */ @Deprecated protected abstract String onGetSummary(); /** Loading @@ -217,4 +230,12 @@ public abstract class SettingInjectorService extends Service { * @return the {@link android.preference.Preference#isEnabled()} value */ protected abstract boolean onGetEnabled(); /** * Sends a broadcast to refresh the injected settings on location settings page. */ public static final void refreshSettings(Context context) { Intent intent = new Intent(ACTION_INJECTED_SETTING_CHANGED); context.sendBroadcast(intent); } } packages/SettingsLib/res/values/strings.xml +4 −0 Original line number Diff line number Diff line Loading @@ -831,6 +831,10 @@ <!-- Toast message shown when setting a new local backup password fails due to the user not supplying the correct existing password. The phrasing here is deliberately quite general. [CHAR LIMIT=80] --> <string name="local_backup_password_toast_validation_failure">Failure setting backup password</string> <!-- [CHAR LIMIT=30] Location mode screen, temporary summary text to show as the status of a location setting injected by an external app while the app is being queried for the actual value --> <string name="loading_injected_setting_summary">Loading\u2026</string> <!-- Name of each color mode for the display. [CHAR LIMIT=40] --> <string-array name="color_mode_names"> <item>Vibrant (default)</item> Loading packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java +62 −69 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.os.Messenger; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.util.ArraySet; import android.util.AttributeSet; import android.util.IconDrawableFactory; import android.util.Log; Loading @@ -44,11 +45,16 @@ import android.util.Xml; import androidx.preference.Preference; import com.android.settingslib.R; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.HashSet; import java.util.Iterator; import java.util.List; Loading Loading @@ -102,7 +108,7 @@ public class SettingsInjector { public SettingsInjector(Context context) { mContext = context; mSettings = new HashSet<Setting>(); mHandler = new StatusLoadingHandler(); mHandler = new StatusLoadingHandler(mSettings); } /** Loading Loading @@ -165,7 +171,7 @@ public class SettingsInjector { Log.e(TAG, "Can't get ApplicationInfo for " + setting.packageName, e); } preference.setTitle(setting.title); preference.setSummary(null); preference.setSummary(R.string.loading_injected_setting_summary); preference.setIcon(appIcon); preference.setOnPreferenceClickListener(new ServiceSettingClickedListener(setting)); } Loading @@ -180,6 +186,7 @@ public class SettingsInjector { final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); final List<UserHandle> profiles = um.getUserProfiles(); ArrayList<Preference> prefs = new ArrayList<>(); mSettings.clear(); for (UserHandle userHandle : profiles) { if (profileId == UserHandle.USER_CURRENT || profileId == userHandle.getIdentifier()) { Iterable<InjectedSetting> settings = getSettings(userHandle); Loading Loading @@ -363,31 +370,28 @@ public class SettingsInjector { * SettingInjectorService}, so to reduce memory pressure we don't want to load too many at * once. */ private final class StatusLoadingHandler extends Handler { private static final class StatusLoadingHandler extends Handler { /** * References all the injected settings. */ WeakReference<Set<Setting>> mAllSettings; /** * Settings whose status values need to be loaded. A set is used to prevent redundant loads. */ private Set<Setting> mSettingsToLoad = new HashSet<Setting>(); private Deque<Setting> mSettingsToLoad = new ArrayDeque<Setting>(); /** * Settings that are being loaded now and haven't timed out. In practice this should have * zero or one elements. */ private Set<Setting> mSettingsBeingLoaded = new HashSet<Setting>(); /** * Settings that are being loaded but have timed out. If only one setting has timed out, we * will go ahead and start loading the next setting so that one slow load won't delay the * load of the other settings. */ private Set<Setting> mTimedOutSettings = new HashSet<Setting>(); private boolean mReloadRequested; private Set<Setting> mSettingsBeingLoaded = new ArraySet<Setting>(); private StatusLoadingHandler() { public StatusLoadingHandler(Set<Setting> allSettings) { super(Looper.getMainLooper()); mAllSettings = new WeakReference<>(allSettings); } @Override public void handleMessage(Message msg) { if (Log.isLoggable(TAG, Log.DEBUG)) { Loading @@ -396,20 +400,24 @@ public class SettingsInjector { // Update state in response to message switch (msg.what) { case WHAT_RELOAD: mReloadRequested = true; case WHAT_RELOAD: { final Set<Setting> allSettings = mAllSettings.get(); if (allSettings != null) { // Reload requested, so must reload all settings mSettingsToLoad.clear(); mSettingsToLoad.addAll(allSettings); } break; } case WHAT_RECEIVED_STATUS: final Setting receivedSetting = (Setting) msg.obj; receivedSetting.maybeLogElapsedTime(); mSettingsBeingLoaded.remove(receivedSetting); mTimedOutSettings.remove(receivedSetting); removeMessages(WHAT_TIMEOUT, receivedSetting); break; case WHAT_TIMEOUT: final Setting timedOutSetting = (Setting) msg.obj; mSettingsBeingLoaded.remove(timedOutSetting); mTimedOutSettings.add(timedOutSetting); if (Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Timed out after " + timedOutSetting.getElapsedTime() + " millis trying to get status for: " + timedOutSetting); Loading @@ -421,37 +429,22 @@ public class SettingsInjector { // Decide whether to load additional settings based on the new state. Start by seeing // if we have headroom to load another setting. if (mSettingsBeingLoaded.size() > 0 || mTimedOutSettings.size() > 1) { if (mSettingsBeingLoaded.size() > 0) { // Don't load any more settings until one of the pending settings has completed. // To reduce memory pressure, we want to be loading at most one setting (plus at // most one timed-out setting) at a time. This means we'll be responsible for // bringing in at most two services. // To reduce memory pressure, we want to be loading at most one setting. if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "too many services already live for " + msg + ", " + this); } return; } if (mReloadRequested && mSettingsToLoad.isEmpty() && mSettingsBeingLoaded.isEmpty() && mTimedOutSettings.isEmpty()) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "reloading because idle and reload requesteed " + msg + ", " + this); } // Reload requested, so must reload all settings mSettingsToLoad.addAll(mSettings); mReloadRequested = false; } // Remove the next setting to load from the queue, if any Iterator<Setting> iter = mSettingsToLoad.iterator(); if (!iter.hasNext()) { if (mSettingsToLoad.isEmpty()) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "nothing left to do for " + msg + ", " + this); } return; } Setting setting = iter.next(); iter.remove(); Setting setting = mSettingsToLoad.removeFirst(); // Request the status value setting.startService(); Loading @@ -473,21 +466,48 @@ public class SettingsInjector { return "StatusLoadingHandler{" + "mSettingsToLoad=" + mSettingsToLoad + ", mSettingsBeingLoaded=" + mSettingsBeingLoaded + ", mTimedOutSettings=" + mTimedOutSettings + ", mReloadRequested=" + mReloadRequested + '}'; } } private static class MessengerHandler extends Handler { private WeakReference<Setting> mSettingRef; private Handler mHandler; public MessengerHandler(Setting setting, Handler handler) { mSettingRef = new WeakReference(setting); mHandler = handler; } @Override public void handleMessage(Message msg) { final Setting setting = mSettingRef.get(); if (setting == null) { return; } final Preference preference = setting.preference; Bundle bundle = msg.getData(); boolean enabled = bundle.getBoolean(SettingInjectorService.ENABLED_KEY, true); String summary = bundle.getString(SettingInjectorService.SUMMARY_KEY, null); if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, setting + ": received " + msg + ", bundle: " + bundle); } preference.setSummary(summary); preference.setEnabled(enabled); mHandler.sendMessage( mHandler.obtainMessage(WHAT_RECEIVED_STATUS, setting)); } } /** * Represents an injected setting and the corresponding preference. */ protected final class Setting { public final InjectedSetting setting; public final Preference preference; public long startMillis; public Setting(InjectedSetting setting, Preference preference) { this.setting = setting; this.preference = preference; Loading @@ -501,20 +521,6 @@ public class SettingsInjector { '}'; } /** * Returns true if they both have the same {@link #setting} value. Ignores mutable * {@link #preference} and {@link #startMillis} so that it's safe to use in sets. */ @Override public boolean equals(Object o) { return this == o || o instanceof Setting && setting.equals(((Setting) o).setting); } @Override public int hashCode() { return setting.hashCode(); } /** * Starts the service to fetch for the current status for the setting, and updates the * preference when the service replies. Loading @@ -529,20 +535,7 @@ public class SettingsInjector { } return; } Handler handler = new Handler() { @Override public void handleMessage(Message msg) { Bundle bundle = msg.getData(); boolean enabled = bundle.getBoolean(SettingInjectorService.ENABLED_KEY, true); if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, setting + ": received " + msg + ", bundle: " + bundle); } preference.setSummary(null); preference.setEnabled(enabled); mHandler.sendMessage( mHandler.obtainMessage(WHAT_RECEIVED_STATUS, Setting.this)); } }; Handler handler = new MessengerHandler(this, mHandler); Messenger messenger = new Messenger(handler); Intent intent = setting.getServiceIntent(); Loading Loading
api/current.txt +2 −1 Original line number Diff line number Diff line Loading @@ -22823,9 +22823,10 @@ package android.location { ctor public SettingInjectorService(java.lang.String); method public final android.os.IBinder onBind(android.content.Intent); method protected abstract boolean onGetEnabled(); method protected abstract deprecated java.lang.String onGetSummary(); method protected abstract java.lang.String onGetSummary(); method public final void onStart(android.content.Intent, int); method public final int onStartCommand(android.content.Intent, int, int); method public static final void refreshSettings(android.content.Context); field public static final java.lang.String ACTION_INJECTED_SETTING_CHANGED = "android.location.InjectedSettingChanged"; field public static final java.lang.String ACTION_SERVICE_INTENT = "android.location.SettingInjectorService"; field public static final java.lang.String ATTRIBUTES_NAME = "injected-location-setting";
location/java/android/location/SettingInjectorService.java +44 −23 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.location; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.IBinder; Loading @@ -26,7 +27,7 @@ import android.os.RemoteException; import android.util.Log; /** * Dynamically specifies the enabled status of a preference injected into * Dynamically specifies the summary (subtitle) and enabled status of a preference injected into * the list of app settings displayed by the system settings app * <p/> * For use only by apps that are included in the system image, for preferences that affect multiple Loading Loading @@ -71,12 +72,13 @@ import android.util.Log; * </ul> * * To ensure a good user experience, your {@link android.app.Application#onCreate()}, * and {@link #onGetEnabled()} methods must all be fast. If either is slow, * it can delay the display of settings values for other apps as well. Note further that these * methods are called on your app's UI thread. * {@link #onGetSummary()}, and {@link #onGetEnabled()} methods must all be fast. If any are slow, * it can delay the display of settings values for other apps as well. Note further that all are * called on your app's UI thread. * <p/> * For compactness, only one copy of a given setting should be injected. If each account has a * distinct value for the setting, then only {@code settingsActivity} should display the value for * distinct value for the setting, then the {@link #onGetSummary()} value should represent a summary * of the state across all of the accounts and {@code settingsActivity} should display the value for * each account. */ public abstract class SettingInjectorService extends Service { Loading Loading @@ -107,6 +109,14 @@ public abstract class SettingInjectorService extends Service { public static final String ACTION_INJECTED_SETTING_CHANGED = "android.location.InjectedSettingChanged"; /** * Name of the bundle key for the string specifying the summary for the setting (e.g., "ON" or * "OFF"). * * @hide */ public static final String SUMMARY_KEY = "summary"; /** * Name of the bundle key for the string specifying whether the setting is currently enabled. * Loading Loading @@ -150,36 +160,41 @@ public abstract class SettingInjectorService extends Service { } private void onHandleIntent(Intent intent) { boolean enabled; String summary = null; boolean enabled = false; try { summary = onGetSummary(); enabled = onGetEnabled(); } catch (RuntimeException e) { // Exception. Send status anyway, so that settings injector can immediately start // loading the status of the next setting. sendStatus(intent, true); throw e; } finally { // If exception happens, send status anyway, so that settings injector can immediately // start loading the status of the next setting. But leave the exception uncaught to // crash the injector service itself. sendStatus(intent, summary, enabled); } sendStatus(intent, enabled); } /** * Send the enabled values back to the caller via the messenger encoded in the * intent. */ private void sendStatus(Intent intent, boolean enabled) { private void sendStatus(Intent intent, String summary, boolean enabled) { Messenger messenger = intent.getParcelableExtra(MESSENGER_KEY); // Bail out to avoid crashing GmsCore with incoming malicious Intent. if (messenger == null) { return; } Message message = Message.obtain(); Bundle bundle = new Bundle(); bundle.putString(SUMMARY_KEY, summary); bundle.putBoolean(ENABLED_KEY, enabled); message.setData(bundle); if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, mName + ": received " + intent Log.d(TAG, mName + ": received " + intent + ", summary=" + summary + ", enabled=" + enabled + ", sending message: " + message); } Messenger messenger = intent.getParcelableExtra(MESSENGER_KEY); try { messenger.send(message); } catch (RemoteException e) { Loading @@ -188,14 +203,12 @@ public abstract class SettingInjectorService extends Service { } /** * This method is no longer called, because status values are no longer shown for any injected * setting. * * @return ignored * Returns the {@link android.preference.Preference#getSummary()} value (allowed to be null or * empty). Should not perform unpredictably-long operations such as network access--see the * running-time comments in the class-level javadoc. * * @deprecated not called any more * @return the {@link android.preference.Preference#getSummary()} value */ @Deprecated protected abstract String onGetSummary(); /** Loading @@ -217,4 +230,12 @@ public abstract class SettingInjectorService extends Service { * @return the {@link android.preference.Preference#isEnabled()} value */ protected abstract boolean onGetEnabled(); /** * Sends a broadcast to refresh the injected settings on location settings page. */ public static final void refreshSettings(Context context) { Intent intent = new Intent(ACTION_INJECTED_SETTING_CHANGED); context.sendBroadcast(intent); } }
packages/SettingsLib/res/values/strings.xml +4 −0 Original line number Diff line number Diff line Loading @@ -831,6 +831,10 @@ <!-- Toast message shown when setting a new local backup password fails due to the user not supplying the correct existing password. The phrasing here is deliberately quite general. [CHAR LIMIT=80] --> <string name="local_backup_password_toast_validation_failure">Failure setting backup password</string> <!-- [CHAR LIMIT=30] Location mode screen, temporary summary text to show as the status of a location setting injected by an external app while the app is being queried for the actual value --> <string name="loading_injected_setting_summary">Loading\u2026</string> <!-- Name of each color mode for the display. [CHAR LIMIT=40] --> <string-array name="color_mode_names"> <item>Vibrant (default)</item> Loading
packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java +62 −69 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.os.Messenger; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.util.ArraySet; import android.util.AttributeSet; import android.util.IconDrawableFactory; import android.util.Log; Loading @@ -44,11 +45,16 @@ import android.util.Xml; import androidx.preference.Preference; import com.android.settingslib.R; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.HashSet; import java.util.Iterator; import java.util.List; Loading Loading @@ -102,7 +108,7 @@ public class SettingsInjector { public SettingsInjector(Context context) { mContext = context; mSettings = new HashSet<Setting>(); mHandler = new StatusLoadingHandler(); mHandler = new StatusLoadingHandler(mSettings); } /** Loading Loading @@ -165,7 +171,7 @@ public class SettingsInjector { Log.e(TAG, "Can't get ApplicationInfo for " + setting.packageName, e); } preference.setTitle(setting.title); preference.setSummary(null); preference.setSummary(R.string.loading_injected_setting_summary); preference.setIcon(appIcon); preference.setOnPreferenceClickListener(new ServiceSettingClickedListener(setting)); } Loading @@ -180,6 +186,7 @@ public class SettingsInjector { final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); final List<UserHandle> profiles = um.getUserProfiles(); ArrayList<Preference> prefs = new ArrayList<>(); mSettings.clear(); for (UserHandle userHandle : profiles) { if (profileId == UserHandle.USER_CURRENT || profileId == userHandle.getIdentifier()) { Iterable<InjectedSetting> settings = getSettings(userHandle); Loading Loading @@ -363,31 +370,28 @@ public class SettingsInjector { * SettingInjectorService}, so to reduce memory pressure we don't want to load too many at * once. */ private final class StatusLoadingHandler extends Handler { private static final class StatusLoadingHandler extends Handler { /** * References all the injected settings. */ WeakReference<Set<Setting>> mAllSettings; /** * Settings whose status values need to be loaded. A set is used to prevent redundant loads. */ private Set<Setting> mSettingsToLoad = new HashSet<Setting>(); private Deque<Setting> mSettingsToLoad = new ArrayDeque<Setting>(); /** * Settings that are being loaded now and haven't timed out. In practice this should have * zero or one elements. */ private Set<Setting> mSettingsBeingLoaded = new HashSet<Setting>(); /** * Settings that are being loaded but have timed out. If only one setting has timed out, we * will go ahead and start loading the next setting so that one slow load won't delay the * load of the other settings. */ private Set<Setting> mTimedOutSettings = new HashSet<Setting>(); private boolean mReloadRequested; private Set<Setting> mSettingsBeingLoaded = new ArraySet<Setting>(); private StatusLoadingHandler() { public StatusLoadingHandler(Set<Setting> allSettings) { super(Looper.getMainLooper()); mAllSettings = new WeakReference<>(allSettings); } @Override public void handleMessage(Message msg) { if (Log.isLoggable(TAG, Log.DEBUG)) { Loading @@ -396,20 +400,24 @@ public class SettingsInjector { // Update state in response to message switch (msg.what) { case WHAT_RELOAD: mReloadRequested = true; case WHAT_RELOAD: { final Set<Setting> allSettings = mAllSettings.get(); if (allSettings != null) { // Reload requested, so must reload all settings mSettingsToLoad.clear(); mSettingsToLoad.addAll(allSettings); } break; } case WHAT_RECEIVED_STATUS: final Setting receivedSetting = (Setting) msg.obj; receivedSetting.maybeLogElapsedTime(); mSettingsBeingLoaded.remove(receivedSetting); mTimedOutSettings.remove(receivedSetting); removeMessages(WHAT_TIMEOUT, receivedSetting); break; case WHAT_TIMEOUT: final Setting timedOutSetting = (Setting) msg.obj; mSettingsBeingLoaded.remove(timedOutSetting); mTimedOutSettings.add(timedOutSetting); if (Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Timed out after " + timedOutSetting.getElapsedTime() + " millis trying to get status for: " + timedOutSetting); Loading @@ -421,37 +429,22 @@ public class SettingsInjector { // Decide whether to load additional settings based on the new state. Start by seeing // if we have headroom to load another setting. if (mSettingsBeingLoaded.size() > 0 || mTimedOutSettings.size() > 1) { if (mSettingsBeingLoaded.size() > 0) { // Don't load any more settings until one of the pending settings has completed. // To reduce memory pressure, we want to be loading at most one setting (plus at // most one timed-out setting) at a time. This means we'll be responsible for // bringing in at most two services. // To reduce memory pressure, we want to be loading at most one setting. if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "too many services already live for " + msg + ", " + this); } return; } if (mReloadRequested && mSettingsToLoad.isEmpty() && mSettingsBeingLoaded.isEmpty() && mTimedOutSettings.isEmpty()) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "reloading because idle and reload requesteed " + msg + ", " + this); } // Reload requested, so must reload all settings mSettingsToLoad.addAll(mSettings); mReloadRequested = false; } // Remove the next setting to load from the queue, if any Iterator<Setting> iter = mSettingsToLoad.iterator(); if (!iter.hasNext()) { if (mSettingsToLoad.isEmpty()) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "nothing left to do for " + msg + ", " + this); } return; } Setting setting = iter.next(); iter.remove(); Setting setting = mSettingsToLoad.removeFirst(); // Request the status value setting.startService(); Loading @@ -473,21 +466,48 @@ public class SettingsInjector { return "StatusLoadingHandler{" + "mSettingsToLoad=" + mSettingsToLoad + ", mSettingsBeingLoaded=" + mSettingsBeingLoaded + ", mTimedOutSettings=" + mTimedOutSettings + ", mReloadRequested=" + mReloadRequested + '}'; } } private static class MessengerHandler extends Handler { private WeakReference<Setting> mSettingRef; private Handler mHandler; public MessengerHandler(Setting setting, Handler handler) { mSettingRef = new WeakReference(setting); mHandler = handler; } @Override public void handleMessage(Message msg) { final Setting setting = mSettingRef.get(); if (setting == null) { return; } final Preference preference = setting.preference; Bundle bundle = msg.getData(); boolean enabled = bundle.getBoolean(SettingInjectorService.ENABLED_KEY, true); String summary = bundle.getString(SettingInjectorService.SUMMARY_KEY, null); if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, setting + ": received " + msg + ", bundle: " + bundle); } preference.setSummary(summary); preference.setEnabled(enabled); mHandler.sendMessage( mHandler.obtainMessage(WHAT_RECEIVED_STATUS, setting)); } } /** * Represents an injected setting and the corresponding preference. */ protected final class Setting { public final InjectedSetting setting; public final Preference preference; public long startMillis; public Setting(InjectedSetting setting, Preference preference) { this.setting = setting; this.preference = preference; Loading @@ -501,20 +521,6 @@ public class SettingsInjector { '}'; } /** * Returns true if they both have the same {@link #setting} value. Ignores mutable * {@link #preference} and {@link #startMillis} so that it's safe to use in sets. */ @Override public boolean equals(Object o) { return this == o || o instanceof Setting && setting.equals(((Setting) o).setting); } @Override public int hashCode() { return setting.hashCode(); } /** * Starts the service to fetch for the current status for the setting, and updates the * preference when the service replies. Loading @@ -529,20 +535,7 @@ public class SettingsInjector { } return; } Handler handler = new Handler() { @Override public void handleMessage(Message msg) { Bundle bundle = msg.getData(); boolean enabled = bundle.getBoolean(SettingInjectorService.ENABLED_KEY, true); if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, setting + ": received " + msg + ", bundle: " + bundle); } preference.setSummary(null); preference.setEnabled(enabled); mHandler.sendMessage( mHandler.obtainMessage(WHAT_RECEIVED_STATUS, Setting.this)); } }; Handler handler = new MessengerHandler(this, mHandler); Messenger messenger = new Messenger(handler); Intent intent = setting.getServiceIntent(); Loading