SettingInjectorService.java revision 4a7c49c81f021ebb01c1ac06737b4e705f212783
1fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill/*
2fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * Copyright (C) 2013 The Android Open Source Project
3fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *
4fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * Licensed under the Apache License, Version 2.0 (the "License");
5fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * you may not use this file except in compliance with the License.
6fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * You may obtain a copy of the License at
7fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *
8fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *      http://www.apache.org/licenses/LICENSE-2.0
9fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *
10fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * Unless required by applicable law or agreed to in writing, software
11fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * distributed under the License is distributed on an "AS IS" BASIS,
12fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * See the License for the specific language governing permissions and
14fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * limitations under the License.
15fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill */
16fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
17fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillpackage android.location;
18fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
19fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.app.IntentService;
20fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.content.Intent;
21fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.os.Bundle;
22fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.os.Message;
23fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.os.Messenger;
24fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.os.RemoteException;
25fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.preference.Preference;
26fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.util.Log;
27fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
28fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill/**
29fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * Dynamically specifies the summary (subtile) and enabled status of a preference injected into
304a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill * the "Settings > Location > Location services" list.
31fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *
32fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * The location services list is intended for use only by preferences that affect multiple apps from
33fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * the same developer. Location settings that apply only to one app should be shown within that app,
34fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * rather than in the system settings.
35fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *
36fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * To add a preference to the list, a subclass of {@link SettingInjectorService} must be declared in
37fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * the manifest as so:
384a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill *
39fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * <pre>
404a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill *     &lt;service android:name="com.example.android.injector.MyInjectorService" &gt;
414a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill *         &lt;intent-filter&gt;
424a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill *             &lt;action android:name="com.android.settings.InjectedLocationSetting" /&gt;
434a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill *         &lt;/intent-filter&gt;
44fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *
454a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill *         &lt;meta-data
46fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *             android:name="com.android.settings.InjectedLocationSetting"
474a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill *             android:resource="@xml/my_injected_location_setting" /&gt;
484a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill *     &lt;/service&gt;
49fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * </pre>
50fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * The resource file specifies the static data for the setting:
51fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * <pre>
524a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill *     &lt;injected-location-setting xmlns:android="http://schemas.android.com/apk/res/android"
53fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *         android:label="@string/injected_setting_label"
54fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *         android:icon="@drawable/ic_launcher"
55fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *         android:settingsActivity="com.example.android.injector.MySettingActivity"
564a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill *     /&gt;
57fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * </pre>
58fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * Here:
59fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * <ul>
60fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *     <li>label: The {@link Preference#getTitle()} value. The title should make it clear which apps
61fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *     are affected by the setting, typically by including the name of the developer. For example,
62fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *     "Acme Corp. ads preferences." </li>
63fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *
64fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *     <li>icon: The {@link Preference#getIcon()} value. Typically this will be a generic icon for
65fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *     the developer rather than the icon for an individual app.</li>
66fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *
67fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *     <li>settingsActivity: the activity which is launched to allow the user to modify the setting
68fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *     value  The activity must be in the same package as the subclass of
69fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *     {@link SettingInjectorService}. The activity should use your own branding to help emphasize
70fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *     to the user that it is not part of the system settings.</li>
71fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * </ul>
72fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *
73184e75146cb17f8695dffba69e0ca8d80b350af3Tom O'Neill * To ensure a good user experience, your {@link #onHandleIntent(Intent)} must complete within
74184e75146cb17f8695dffba69e0ca8d80b350af3Tom O'Neill * 200 msec even if your app is not already running. This means that both
75184e75146cb17f8695dffba69e0ca8d80b350af3Tom O'Neill * {@link android.app.Application#onCreate()} and {@link #getStatus()} must be fast. If you exceed
76184e75146cb17f8695dffba69e0ca8d80b350af3Tom O'Neill * this time, then this can delay the retrieval of settings status for other apps as well.
77184e75146cb17f8695dffba69e0ca8d80b350af3Tom O'Neill *
78fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * For consistency, the label and {@link #getStatus()} values should be provided in all of the
79fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * locales supported by the system settings app. The text should not contain offensive language.
80fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *
81fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * For compactness, only one copy of a given setting should be injected. If each account has a
82fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * distinct value for the setting, then the {@link #getStatus()} value should represent a summary of
83fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * the state across all of the accounts and {@code settingsActivity} should display the value for
84fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * each account.
85fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *
86fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * Apps that violate these guidelines will be taken down from the Google Play Store and/or flagged
87fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * as malware.
88fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill */
89fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill// TODO: is there a public list of supported locales?
90fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill// TODO: is there a public list of guidelines for settings text?
91184e75146cb17f8695dffba69e0ca8d80b350af3Tom O'Neill// TODO: would a bound service be better? E.g., we could just disconnect if a service took too long
92fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillpublic abstract class SettingInjectorService extends IntentService {
93fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
944a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill    private static final String TAG = "SettingInjectorService";
954a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill
96fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    /**
974a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill     * Name of the bundle key for the string specifying the summary for the setting (e.g., "ON" or
98fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     * "OFF").
99fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     *
100fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     * @hide
101fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     */
1024a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill    public static final String SUMMARY_KEY = "summary";
1034a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill
1044a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill    /**
1054a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill     * TODO: delete after switching SettingsInjector to use {@link #SUMMARY_KEY}.
1064a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill     *
1074a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill     * @deprecated use {@link #SUMMARY_KEY}
1084a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill     *
1094a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill     * @hide
1104a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill     */
1114a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill    @Deprecated
112fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    public static final String STATUS_KEY = "status";
113fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
114fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    /**
115fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     * Name of the bundle key for the string specifying whether the setting is currently enabled.
116fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     *
117fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     * @hide
118fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     */
119fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    public static final String ENABLED_KEY = "enabled";
120fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
121fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    /**
122fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     * Name of the intent key used to specify the messenger
123fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     *
124fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     * @hide
125fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     */
126fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    public static final String MESSENGER_KEY = "messenger";
127fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
128184e75146cb17f8695dffba69e0ca8d80b350af3Tom O'Neill    /**
129184e75146cb17f8695dffba69e0ca8d80b350af3Tom O'Neill     * Intent action a client should broadcast when the value of one of its injected settings has
130184e75146cb17f8695dffba69e0ca8d80b350af3Tom O'Neill     * changed, so that the setting can be updated in the UI.
131184e75146cb17f8695dffba69e0ca8d80b350af3Tom O'Neill     */
1324a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill    public static final String ACTION_INJECTED_SETTING_CHANGED =
1334a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill            "com.android.location.InjectedSettingChanged";
134fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
135fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    /**
1364a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill     * TODO: delete after switching callers to use {@link #ACTION_INJECTED_SETTING_CHANGED}.
137fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     *
1384a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill     * @deprecated use {@link #ACTION_INJECTED_SETTING_CHANGED}
139fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     */
1404a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill    @Deprecated
1414a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill    public static final String UPDATE_INTENT = ACTION_INJECTED_SETTING_CHANGED;
142fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
1434a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill    private final String mName;
144fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
1454a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill    /**
1464a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill     * Constructor.
1474a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill     *
1484a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill     * @param name used to name the worker thread and in log messages
1494a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill     */
1504a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill    public SettingInjectorService(String name) {
1514a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        super(name);
1524a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        mName = name;
153fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    }
154fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
155fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    @Override
156fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    final protected void onHandleIntent(Intent intent) {
157fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        // Get messenger first to ensure intent doesn't get messed with (in case we later decide
158fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        // to pass intent into getStatus())
159fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        Messenger messenger = intent.getParcelableExtra(MESSENGER_KEY);
160fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
1614a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        Status status;
1624a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        try {
1634a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill            status = getStatus();
1644a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        } catch (RuntimeException e) {
1654a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill            Log.e(TAG, mName + ": error getting status", e);
1664a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill            status = null;
1674a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        }
168fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
169fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        // Send the status back to the caller via the messenger
170fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        Message message = Message.obtain();
171fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        Bundle bundle = new Bundle();
1724a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        if (status != null) {
1734a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill            bundle.putString(STATUS_KEY, status.summary);
1744a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill            bundle.putString(SUMMARY_KEY, status.summary);
1754a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill            bundle.putBoolean(ENABLED_KEY, status.enabled);
1764a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        }
177fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        message.setData(bundle);
178fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
1794a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        if (Log.isLoggable(TAG, Log.DEBUG)) {
1804a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill            Log.d(TAG, mName + ": received " + intent + " and " + status
1814a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill                    + ", sending message: " + message);
182fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        }
183fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        try {
184fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill            messenger.send(message);
185fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        } catch (RemoteException e) {
1864a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill            Log.e(TAG, mName + ": sending status failed", e);
187fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        }
188fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    }
189fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
190fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    /**
191fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     * Reads the status of the setting.
192fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     */
193fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    protected abstract Status getStatus();
194fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
195fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    /**
196fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     * Dynamic characteristics of an injected location setting.
197fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     */
198fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    public static final class Status {
199fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
2004a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        /**
2014a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill         * The {@link Preference#getSummary()} value
2024a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill         */
203fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        public final String summary;
204fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
2054a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        /**
2064a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill         * The {@link Preference#isEnabled()} value
2074a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill         */
208fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        public final boolean enabled;
209fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
210fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        /**
211fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill         * Constructor.
212c8211ea1cc65560938c31263edce6fcb87016acbTom O'Neill         * <p/>
213c8211ea1cc65560938c31263edce6fcb87016acbTom O'Neill         * Note that to prevent churn in the settings list, there is no support for dynamically
214c8211ea1cc65560938c31263edce6fcb87016acbTom O'Neill         * choosing to hide a setting. Instead you should provide a {@code enabled} value of false,
215c8211ea1cc65560938c31263edce6fcb87016acbTom O'Neill         * which will gray the setting out and disable the link from "Settings > Location"
216c8211ea1cc65560938c31263edce6fcb87016acbTom O'Neill         * to your setting activity. One reason why you might choose to do this is if
217c8211ea1cc65560938c31263edce6fcb87016acbTom O'Neill         * {@link android.provider.Settings.Secure#getLocationMode(android.content.ContentResolver)}
218c8211ea1cc65560938c31263edce6fcb87016acbTom O'Neill         * is {@link android.provider.Settings.Secure#LOCATION_MODE_OFF}.
219fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill         *
2204a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill         * It is possible that the user may click on the setting before you return a false value for
2214a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill         * {@code enabled}, so your settings activity must handle the case where it is invoked even
2224a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill         * though the setting is disabled. The simplest approach may be to simply call
2234a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill         * {@link android.app.Activity#finish()} when disabled.
2244a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill         *
225c8211ea1cc65560938c31263edce6fcb87016acbTom O'Neill         * @param summary the {@link Preference#getSummary()} value (allowed to be null or empty)
226fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill         * @param enabled the {@link Preference#isEnabled()} value
227fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill         */
228fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        public Status(String summary, boolean enabled) {
229fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill            this.summary = summary;
230fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill            this.enabled = enabled;
231fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        }
232fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
233fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        @Override
234fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        public String toString() {
235fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill            return "Status{summary='" + summary + '\'' + ", enabled=" + enabled + '}';
236fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        }
237fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    }
238fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill}
239