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
19cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neillimport android.app.Service;
20fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.content.Intent;
21fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.os.Bundle;
22cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neillimport android.os.IBinder;
23fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.os.Message;
24fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.os.Messenger;
25fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.os.RemoteException;
26fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.util.Log;
27fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
28fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill/**
29248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill * Dynamically specifies the enabled status of a preference injected into
30cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill * the list of app settings displayed by the system settings app
31cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill * <p/>
32cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill * For use only by apps that are included in the system image, for preferences that affect multiple
33cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill * apps. Location settings that apply only to one app should be shown within that app,
34fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * rather than in the system settings.
35cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill * <p/>
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;
42546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill *             &lt;action android:name="android.location.SettingInjectorService" /&gt;
434a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill *         &lt;/intent-filter&gt;
44fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *
454a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill *         &lt;meta-data
46546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill *             android:name="android.location.SettingInjectorService"
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"
53546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill *         android:title="@string/injected_setting_title"
54546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill *         android:icon="@drawable/ic_acme_corp"
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>
60546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill *     <li>title: The {@link android.preference.Preference#getTitle()} value. The title should make
61546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill *     it clear which apps are affected by the setting, typically by including the name of the
62546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill *     developer. For example, "Acme Corp. ads preferences." </li>
63fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *
64546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill *     <li>icon: The {@link android.preference.Preference#getIcon()} value. Typically this will be a
65546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill *     generic icon for 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
68546113d4c290f36bf21b1e9c7b93d1592df17fceTom 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 *
73cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill * To ensure a good user experience, your {@link android.app.Application#onCreate()},
74248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill * and {@link #onGetEnabled()} methods must all be fast. If either is slow,
75248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill * it can delay the display of settings values for other apps as well. Note further that these
76248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill * methods are called on your app's UI thread.
77cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill * <p/>
78fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * For compactness, only one copy of a given setting should be injected. If each account has a
79248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill * distinct value for the setting, then only {@code settingsActivity} should display the value for
80fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * each account.
81fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill */
82cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neillpublic abstract class SettingInjectorService extends Service {
83fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
844a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill    private static final String TAG = "SettingInjectorService";
854a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill
86fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    /**
87546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill     * Intent action that must be declared in the manifest for the subclass. Used to start the
88546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill     * service to read the dynamic status for the setting.
89546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill     */
90546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill    public static final String ACTION_SERVICE_INTENT = "android.location.SettingInjectorService";
91546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill
92546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill    /**
93546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill     * Name of the meta-data tag used to specify the resource file that includes the settings
94546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill     * attributes.
95546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill     */
96546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill    public static final String META_DATA_NAME = "android.location.SettingInjectorService";
97546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill
98546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill    /**
99546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill     * Name of the XML tag that includes the attributes for the setting.
100546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill     */
101546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill    public static final String ATTRIBUTES_NAME = "injected-location-setting";
102546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill
103546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill    /**
104546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill     * Intent action a client should broadcast when the value of one of its injected settings has
105546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill     * changed, so that the setting can be updated in the UI.
106546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill     */
107546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill    public static final String ACTION_INJECTED_SETTING_CHANGED =
108546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill            "android.location.InjectedSettingChanged";
109546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill
110546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill    /**
111fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     * Name of the bundle key for the string specifying whether the setting is currently enabled.
112fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     *
113fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     * @hide
114fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     */
115fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    public static final String ENABLED_KEY = "enabled";
116fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
117fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    /**
118fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     * Name of the intent key used to specify the messenger
119fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     *
120fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     * @hide
121fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     */
122fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    public static final String MESSENGER_KEY = "messenger";
123fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
1244a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill    private final String mName;
125fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
1264a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill    /**
1274a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill     * Constructor.
1284a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill     *
129cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     * @param name used to identify your subclass in log messages
1304a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill     */
1314a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill    public SettingInjectorService(String name) {
1324a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        mName = name;
133fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    }
134fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
135fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    @Override
136cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    public final IBinder onBind(Intent intent) {
137cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill        return null;
138cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    }
139cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill
140cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    @Override
141cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    public final void onStart(Intent intent, int startId) {
142cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill        super.onStart(intent, startId);
143cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    }
144cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill
145cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    @Override
146cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    public final int onStartCommand(Intent intent, int flags, int startId) {
147cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill        onHandleIntent(intent);
148cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill        stopSelf(startId);
149cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill        return START_NOT_STICKY;
150cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    }
151cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill
152cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    private void onHandleIntent(Intent intent) {
153cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill
154cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill        boolean enabled;
1554a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        try {
156cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill            enabled = onGetEnabled();
1574a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        } catch (RuntimeException e) {
158cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill            // Exception. Send status anyway, so that settings injector can immediately start
159cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill            // loading the status of the next setting.
160248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill            sendStatus(intent, true);
161cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill            throw e;
1624a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        }
163fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
164248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill        sendStatus(intent, enabled);
165cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    }
166cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill
167cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    /**
168248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill     * Send the enabled values back to the caller via the messenger encoded in the
169cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     * intent.
170cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     */
171248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill    private void sendStatus(Intent intent, boolean enabled) {
172fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        Message message = Message.obtain();
173fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        Bundle bundle = new Bundle();
174cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill        bundle.putBoolean(ENABLED_KEY, enabled);
175fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        message.setData(bundle);
176fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
1774a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        if (Log.isLoggable(TAG, Log.DEBUG)) {
178248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill            Log.d(TAG, mName + ": received " + intent
179cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                    + ", enabled=" + enabled + ", sending message: " + message);
180fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        }
181cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill
182cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill        Messenger messenger = intent.getParcelableExtra(MESSENGER_KEY);
183fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        try {
184fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill            messenger.send(message);
185fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        } catch (RemoteException e) {
186cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill            Log.e(TAG, mName + ": sending dynamic status failed", e);
187fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        }
188fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    }
189fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
190fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    /**
191248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill     * This method is no longer called, because status values are no longer shown for any injected
192248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill     * setting.
193546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill     *
194248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill     * @return ignored
195248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill     *
196248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill     * @deprecated not called any more
197fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     */
198248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill    @Deprecated
19917c5e79496bc1e2d53bc3c4e33bad4b39b80c36dTom O'Neill    protected abstract String onGetSummary();
200fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
201fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    /**
202cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     * Returns the {@link android.preference.Preference#isEnabled()} value. Should not perform
203cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     * unpredictably-long operations such as network access--see the running-time comments in the
204cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     * class-level javadoc.
205cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     * <p/>
206cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     * Note that to prevent churn in the settings list, there is no support for dynamically choosing
207cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     * to hide a setting. Instead you should have this method return false, which will disable the
208cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     * setting and its link to your setting activity. One reason why you might choose to do this is
209cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     * if {@link android.provider.Settings.Secure#LOCATION_MODE} is {@link
210cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     * android.provider.Settings.Secure#LOCATION_MODE_OFF}.
211cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     * <p/>
212cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     * It is possible that the user may click on the setting before this method returns, so your
213cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     * settings activity must handle the case where it is invoked even though the setting is
214cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     * disabled. The simplest approach may be to simply call {@link android.app.Activity#finish()}
215cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     * when disabled.
216cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     *
217cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill     * @return the {@link android.preference.Preference#isEnabled()} value
218fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     */
219cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    protected abstract boolean onGetEnabled();
220fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill}
221