Settings.java revision 3d384f4ca29d031f7ac3c7f0cc0a2f448a277097
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settings;
18
19import com.android.internal.util.ArrayUtils;
20import com.android.settings.accounts.AccountSyncSettings;
21import com.android.settings.applications.ManageApplications;
22import com.android.settings.bluetooth.BluetoothEnabler;
23import com.android.settings.deviceinfo.Memory;
24import com.android.settings.fuelgauge.PowerUsageSummary;
25import com.android.settings.wifi.WifiEnabler;
26
27import android.content.ComponentName;
28import android.content.Context;
29import android.content.Intent;
30import android.content.pm.ActivityInfo;
31import android.content.pm.PackageManager;
32import android.content.pm.PackageManager.NameNotFoundException;
33import android.os.Bundle;
34import android.os.INetworkManagementService;
35import android.os.RemoteException;
36import android.os.ServiceManager;
37import android.os.UserId;
38import android.preference.Preference;
39import android.preference.PreferenceActivity;
40import android.preference.PreferenceFragment;
41import android.text.TextUtils;
42import android.util.Log;
43import android.view.LayoutInflater;
44import android.view.View;
45import android.view.View.OnClickListener;
46import android.view.ViewGroup;
47import android.widget.ArrayAdapter;
48import android.widget.Button;
49import android.widget.ImageView;
50import android.widget.ListAdapter;
51import android.widget.Switch;
52import android.widget.TextView;
53
54import java.util.ArrayList;
55import java.util.HashMap;
56import java.util.List;
57
58/**
59 * Top-level settings activity to handle single pane and double pane UI layout.
60 */
61public class Settings extends PreferenceActivity implements ButtonBarHandler {
62
63    private static final String LOG_TAG = "Settings";
64    private static final String META_DATA_KEY_HEADER_ID =
65        "com.android.settings.TOP_LEVEL_HEADER_ID";
66    private static final String META_DATA_KEY_FRAGMENT_CLASS =
67        "com.android.settings.FRAGMENT_CLASS";
68    private static final String META_DATA_KEY_PARENT_TITLE =
69        "com.android.settings.PARENT_FRAGMENT_TITLE";
70    private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS =
71        "com.android.settings.PARENT_FRAGMENT_CLASS";
72
73    private static final String EXTRA_CLEAR_UI_OPTIONS = "settings:remove_ui_options";
74
75    private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
76    private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";
77
78    private String mFragmentClass;
79    private int mTopLevelHeaderId;
80    private Header mFirstHeader;
81    private Header mCurrentHeader;
82    private Header mParentHeader;
83    private boolean mInLocalHeaderSwitch;
84
85    // Show only these settings for restricted users
86    private int[] SETTINGS_FOR_RESTRICTED = {
87            R.id.wifi_settings,
88            R.id.bluetooth_settings,
89            R.id.sound_settings,
90            R.id.display_settings,
91            R.id.security_settings,
92            R.id.sync_settings,
93            R.id.about_settings
94    };
95
96    private boolean mEnableUserManagement = false;
97
98    // TODO: Update Call Settings based on airplane mode state.
99
100    protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
101    private List<Header> mHeaders;
102
103    @Override
104    protected void onCreate(Bundle savedInstanceState) {
105        if (getIntent().getBooleanExtra(EXTRA_CLEAR_UI_OPTIONS, false)) {
106            getWindow().setUiOptions(0);
107        }
108
109        if (android.provider.Settings.Secure.getInt(getContentResolver(), "multiuser_enabled", -1)
110                > 0) {
111            mEnableUserManagement = true;
112        }
113
114        getMetaData();
115        mInLocalHeaderSwitch = true;
116        super.onCreate(savedInstanceState);
117        mInLocalHeaderSwitch = false;
118
119        if (!onIsHidingHeaders() && onIsMultiPane()) {
120            highlightHeader();
121            // Force the title so that it doesn't get overridden by a direct launch of
122            // a specific settings screen.
123            setTitle(R.string.settings_label);
124        }
125
126        // Retrieve any saved state
127        if (savedInstanceState != null) {
128            mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);
129            mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);
130        }
131
132        // If the current header was saved, switch to it
133        if (savedInstanceState != null && mCurrentHeader != null) {
134            //switchToHeaderLocal(mCurrentHeader);
135            showBreadCrumbs(mCurrentHeader.title, null);
136        }
137
138        if (mParentHeader != null) {
139            setParentTitle(mParentHeader.title, null, new OnClickListener() {
140                public void onClick(View v) {
141                    switchToParent(mParentHeader.fragment);
142                }
143            });
144        }
145
146        // Override up navigation for multi-pane, since we handle it in the fragment breadcrumbs
147        if (onIsMultiPane()) {
148            getActionBar().setDisplayHomeAsUpEnabled(false);
149            getActionBar().setHomeButtonEnabled(false);
150        }
151    }
152
153    @Override
154    protected void onSaveInstanceState(Bundle outState) {
155        super.onSaveInstanceState(outState);
156
157        // Save the current fragment, if it is the same as originally launched
158        if (mCurrentHeader != null) {
159            outState.putParcelable(SAVE_KEY_CURRENT_HEADER, mCurrentHeader);
160        }
161        if (mParentHeader != null) {
162            outState.putParcelable(SAVE_KEY_PARENT_HEADER, mParentHeader);
163        }
164    }
165
166    @Override
167    public void onResume() {
168        super.onResume();
169
170        ListAdapter listAdapter = getListAdapter();
171        if (listAdapter instanceof HeaderAdapter) {
172            ((HeaderAdapter) listAdapter).resume();
173        }
174    }
175
176    @Override
177    public void onPause() {
178        super.onPause();
179
180        ListAdapter listAdapter = getListAdapter();
181        if (listAdapter instanceof HeaderAdapter) {
182            ((HeaderAdapter) listAdapter).pause();
183        }
184    }
185
186    private void switchToHeaderLocal(Header header) {
187        mInLocalHeaderSwitch = true;
188        switchToHeader(header);
189        mInLocalHeaderSwitch = false;
190    }
191
192    @Override
193    public void switchToHeader(Header header) {
194        if (!mInLocalHeaderSwitch) {
195            mCurrentHeader = null;
196            mParentHeader = null;
197        }
198        super.switchToHeader(header);
199    }
200
201    /**
202     * Switch to parent fragment and store the grand parent's info
203     * @param className name of the activity wrapper for the parent fragment.
204     */
205    private void switchToParent(String className) {
206        final ComponentName cn = new ComponentName(this, className);
207        try {
208            final PackageManager pm = getPackageManager();
209            final ActivityInfo parentInfo = pm.getActivityInfo(cn, PackageManager.GET_META_DATA);
210
211            if (parentInfo != null && parentInfo.metaData != null) {
212                String fragmentClass = parentInfo.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
213                CharSequence fragmentTitle = parentInfo.loadLabel(pm);
214                Header parentHeader = new Header();
215                parentHeader.fragment = fragmentClass;
216                parentHeader.title = fragmentTitle;
217                mCurrentHeader = parentHeader;
218
219                switchToHeaderLocal(parentHeader);
220                highlightHeader();
221
222                mParentHeader = new Header();
223                mParentHeader.fragment
224                        = parentInfo.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
225                mParentHeader.title = parentInfo.metaData.getString(META_DATA_KEY_PARENT_TITLE);
226            }
227        } catch (NameNotFoundException nnfe) {
228            Log.w(LOG_TAG, "Could not find parent activity : " + className);
229        }
230    }
231
232    @Override
233    public void onNewIntent(Intent intent) {
234        super.onNewIntent(intent);
235
236        // If it is not launched from history, then reset to top-level
237        if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0
238                && mFirstHeader != null && !onIsHidingHeaders() && onIsMultiPane()) {
239            switchToHeaderLocal(mFirstHeader);
240        }
241    }
242
243    private void highlightHeader() {
244        if (mTopLevelHeaderId != 0) {
245            Integer index = mHeaderIndexMap.get(mTopLevelHeaderId);
246            if (index != null) {
247                getListView().setItemChecked(index, true);
248                getListView().smoothScrollToPosition(index);
249            }
250        }
251    }
252
253    @Override
254    public Intent getIntent() {
255        Intent superIntent = super.getIntent();
256        String startingFragment = getStartingFragmentClass(superIntent);
257        // This is called from super.onCreate, isMultiPane() is not yet reliable
258        // Do not use onIsHidingHeaders either, which relies itself on this method
259        if (startingFragment != null && !onIsMultiPane()) {
260            Intent modIntent = new Intent(superIntent);
261            modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
262            Bundle args = superIntent.getExtras();
263            if (args != null) {
264                args = new Bundle(args);
265            } else {
266                args = new Bundle();
267            }
268            args.putParcelable("intent", superIntent);
269            modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());
270            return modIntent;
271        }
272        return superIntent;
273    }
274
275    /**
276     * Checks if the component name in the intent is different from the Settings class and
277     * returns the class name to load as a fragment.
278     */
279    protected String getStartingFragmentClass(Intent intent) {
280        if (mFragmentClass != null) return mFragmentClass;
281
282        String intentClass = intent.getComponent().getClassName();
283        if (intentClass.equals(getClass().getName())) return null;
284
285        if ("com.android.settings.ManageApplications".equals(intentClass)
286                || "com.android.settings.RunningServices".equals(intentClass)
287                || "com.android.settings.applications.StorageUse".equals(intentClass)) {
288            // Old names of manage apps.
289            intentClass = com.android.settings.applications.ManageApplications.class.getName();
290        }
291
292        return intentClass;
293    }
294
295    /**
296     * Override initial header when an activity-alias is causing Settings to be launched
297     * for a specific fragment encoded in the android:name parameter.
298     */
299    @Override
300    public Header onGetInitialHeader() {
301        String fragmentClass = getStartingFragmentClass(super.getIntent());
302        if (fragmentClass != null) {
303            Header header = new Header();
304            header.fragment = fragmentClass;
305            header.title = getTitle();
306            header.fragmentArguments = getIntent().getExtras();
307            mCurrentHeader = header;
308            return header;
309        }
310
311        return mFirstHeader;
312    }
313
314    @Override
315    public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
316            int titleRes, int shortTitleRes) {
317        Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
318                titleRes, shortTitleRes);
319
320        // some fragments want to avoid split actionbar
321        if (DataUsageSummary.class.getName().equals(fragmentName) ||
322                PowerUsageSummary.class.getName().equals(fragmentName) ||
323                AccountSyncSettings.class.getName().equals(fragmentName) ||
324                UserDictionarySettings.class.getName().equals(fragmentName) ||
325                Memory.class.getName().equals(fragmentName) ||
326                ManageApplications.class.getName().equals(fragmentName) ||
327                WirelessSettings.class.getName().equals(fragmentName) ||
328                SoundSettings.class.getName().equals(fragmentName) ||
329                PrivacySettings.class.getName().equals(fragmentName)) {
330            intent.putExtra(EXTRA_CLEAR_UI_OPTIONS, true);
331        }
332
333        intent.setClass(this, SubSettings.class);
334        return intent;
335    }
336
337    /**
338     * Populate the activity with the top-level headers.
339     */
340    @Override
341    public void onBuildHeaders(List<Header> headers) {
342        loadHeadersFromResource(R.xml.settings_headers, headers);
343
344        updateHeaderList(headers);
345
346        mHeaders = headers;
347    }
348
349    private void updateHeaderList(List<Header> target) {
350        int i = 0;
351        while (i < target.size()) {
352            Header header = target.get(i);
353            // Ids are integers, so downcasting
354            int id = (int) header.id;
355            if (id == R.id.dock_settings) {
356                if (!needsDockSettings())
357                    target.remove(header);
358            } else if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
359                Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);
360            } else if (id == R.id.wifi_settings) {
361                // Remove WiFi Settings if WiFi service is not available.
362                if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
363                    target.remove(header);
364                }
365            } else if (id == R.id.bluetooth_settings) {
366                // Remove Bluetooth Settings if Bluetooth service is not available.
367                if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
368                    target.remove(header);
369                }
370            } else if (id == R.id.data_usage_settings) {
371                // Remove data usage when kernel module not enabled
372                final INetworkManagementService netManager = INetworkManagementService.Stub
373                        .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
374                try {
375                    if (!netManager.isBandwidthControlEnabled()) {
376                        target.remove(header);
377                    }
378                } catch (RemoteException e) {
379                    // ignored
380                }
381            } else if (id == R.id.user_settings) {
382                if (!mEnableUserManagement
383                        || !UserId.MU_ENABLED || UserId.myUserId() != 0
384                        || !getResources().getBoolean(R.bool.enable_user_management)
385                        || Utils.isMonkeyRunning()) {
386                    target.remove(header);
387                }
388            }
389            if (UserId.MU_ENABLED && UserId.myUserId() != 0
390                    && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, id)) {
391                target.remove(header);
392            }
393
394            // Increment if the current one wasn't removed by the Utils code.
395            if (target.get(i) == header) {
396                // Hold on to the first header, when we need to reset to the top-level
397                if (mFirstHeader == null &&
398                        HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {
399                    mFirstHeader = header;
400                }
401                mHeaderIndexMap.put(id, i);
402                i++;
403            }
404        }
405    }
406
407    private boolean needsDockSettings() {
408        return getResources().getBoolean(R.bool.has_dock_settings);
409    }
410
411    private void getMetaData() {
412        try {
413            ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
414                    PackageManager.GET_META_DATA);
415            if (ai == null || ai.metaData == null) return;
416            mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
417            mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
418
419            // Check if it has a parent specified and create a Header object
420            final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
421            String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
422            if (parentFragmentClass != null) {
423                mParentHeader = new Header();
424                mParentHeader.fragment = parentFragmentClass;
425                if (parentHeaderTitleRes != 0) {
426                    mParentHeader.title = getResources().getString(parentHeaderTitleRes);
427                }
428            }
429        } catch (NameNotFoundException nnfe) {
430            // No recovery
431        }
432    }
433
434    @Override
435    public boolean hasNextButton() {
436        return super.hasNextButton();
437    }
438
439    @Override
440    public Button getNextButton() {
441        return super.getNextButton();
442    }
443
444    private static class HeaderAdapter extends ArrayAdapter<Header> {
445        static final int HEADER_TYPE_CATEGORY = 0;
446        static final int HEADER_TYPE_NORMAL = 1;
447        static final int HEADER_TYPE_SWITCH = 2;
448        private static final int HEADER_TYPE_COUNT = HEADER_TYPE_SWITCH + 1;
449
450        private final WifiEnabler mWifiEnabler;
451        private final BluetoothEnabler mBluetoothEnabler;
452
453        private static class HeaderViewHolder {
454            ImageView icon;
455            TextView title;
456            TextView summary;
457            Switch switch_;
458        }
459
460        private LayoutInflater mInflater;
461
462        static int getHeaderType(Header header) {
463            if (header.fragment == null && header.intent == null) {
464                return HEADER_TYPE_CATEGORY;
465            } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
466                return HEADER_TYPE_SWITCH;
467            } else {
468                return HEADER_TYPE_NORMAL;
469            }
470        }
471
472        @Override
473        public int getItemViewType(int position) {
474            Header header = getItem(position);
475            return getHeaderType(header);
476        }
477
478        @Override
479        public boolean areAllItemsEnabled() {
480            return false; // because of categories
481        }
482
483        @Override
484        public boolean isEnabled(int position) {
485            return getItemViewType(position) != HEADER_TYPE_CATEGORY;
486        }
487
488        @Override
489        public int getViewTypeCount() {
490            return HEADER_TYPE_COUNT;
491        }
492
493        @Override
494        public boolean hasStableIds() {
495            return true;
496        }
497
498        public HeaderAdapter(Context context, List<Header> objects) {
499            super(context, 0, objects);
500            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
501
502            // Temp Switches provided as placeholder until the adapter replaces these with actual
503            // Switches inflated from their layouts. Must be done before adapter is set in super
504            mWifiEnabler = new WifiEnabler(context, new Switch(context));
505            mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
506        }
507
508        @Override
509        public View getView(int position, View convertView, ViewGroup parent) {
510            HeaderViewHolder holder;
511            Header header = getItem(position);
512            int headerType = getHeaderType(header);
513            View view = null;
514
515            if (convertView == null) {
516                holder = new HeaderViewHolder();
517                switch (headerType) {
518                    case HEADER_TYPE_CATEGORY:
519                        view = new TextView(getContext(), null,
520                                android.R.attr.listSeparatorTextViewStyle);
521                        holder.title = (TextView) view;
522                        break;
523
524                    case HEADER_TYPE_SWITCH:
525                        view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
526                                false);
527                        holder.icon = (ImageView) view.findViewById(R.id.icon);
528                        holder.title = (TextView)
529                                view.findViewById(com.android.internal.R.id.title);
530                        holder.summary = (TextView)
531                                view.findViewById(com.android.internal.R.id.summary);
532                        holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
533                        break;
534
535                    case HEADER_TYPE_NORMAL:
536                        view = mInflater.inflate(
537                                com.android.internal.R.layout.preference_header_item, parent,
538                                false);
539                        holder.icon = (ImageView) view.findViewById(com.android.internal.R.id.icon);
540                        holder.title = (TextView)
541                                view.findViewById(com.android.internal.R.id.title);
542                        holder.summary = (TextView)
543                                view.findViewById(com.android.internal.R.id.summary);
544                        break;
545                }
546                view.setTag(holder);
547            } else {
548                view = convertView;
549                holder = (HeaderViewHolder) view.getTag();
550            }
551
552            // All view fields must be updated every time, because the view may be recycled
553            switch (headerType) {
554                case HEADER_TYPE_CATEGORY:
555                    holder.title.setText(header.getTitle(getContext().getResources()));
556                    break;
557
558                case HEADER_TYPE_SWITCH:
559                    // Would need a different treatment if the main menu had more switches
560                    if (header.id == R.id.wifi_settings) {
561                        mWifiEnabler.setSwitch(holder.switch_);
562                    } else {
563                        mBluetoothEnabler.setSwitch(holder.switch_);
564                    }
565                    // No break, fall through on purpose to update common fields
566
567                    //$FALL-THROUGH$
568                case HEADER_TYPE_NORMAL:
569                    holder.icon.setImageResource(header.iconRes);
570                    holder.title.setText(header.getTitle(getContext().getResources()));
571                    CharSequence summary = header.getSummary(getContext().getResources());
572                    if (!TextUtils.isEmpty(summary)) {
573                        holder.summary.setVisibility(View.VISIBLE);
574                        holder.summary.setText(summary);
575                    } else {
576                        holder.summary.setVisibility(View.GONE);
577                    }
578                    break;
579            }
580
581            return view;
582        }
583
584        public void resume() {
585            mWifiEnabler.resume();
586            mBluetoothEnabler.resume();
587        }
588
589        public void pause() {
590            mWifiEnabler.pause();
591            mBluetoothEnabler.pause();
592        }
593    }
594
595    @Override
596    public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
597        // Override the fragment title for Wallpaper settings
598        int titleRes = pref.getTitleRes();
599        if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {
600            titleRes = R.string.wallpaper_settings_fragment_title;
601        }
602        startPreferencePanel(pref.getFragment(), pref.getExtras(), titleRes, pref.getTitle(),
603                null, 0);
604        return true;
605    }
606
607    public boolean shouldUpRecreateTask(Intent targetIntent) {
608        return super.shouldUpRecreateTask(new Intent(this, Settings.class));
609    }
610
611    @Override
612    public void setListAdapter(ListAdapter adapter) {
613        if (mHeaders == null) {
614            mHeaders = new ArrayList<Header>();
615            // When the saved state provides the list of headers, onBuildHeaders is not called
616            // Copy the list of Headers from the adapter, preserving their order
617            for (int i = 0; i < adapter.getCount(); i++) {
618                mHeaders.add((Header) adapter.getItem(i));
619            }
620        }
621
622        // Ignore the adapter provided by PreferenceActivity and substitute ours instead
623        super.setListAdapter(new HeaderAdapter(this, mHeaders));
624    }
625
626    /*
627     * Settings subclasses for launching independently.
628     */
629    public static class BluetoothSettingsActivity extends Settings { /* empty */ }
630    public static class WirelessSettingsActivity extends Settings { /* empty */ }
631    public static class TetherSettingsActivity extends Settings { /* empty */ }
632    public static class VpnSettingsActivity extends Settings { /* empty */ }
633    public static class DateTimeSettingsActivity extends Settings { /* empty */ }
634    public static class StorageSettingsActivity extends Settings { /* empty */ }
635    public static class WifiSettingsActivity extends Settings { /* empty */ }
636    public static class WifiP2pSettingsActivity extends Settings { /* empty */ }
637    public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }
638    public static class KeyboardLayoutPickerActivity extends Settings { /* empty */ }
639    public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ }
640    public static class SpellCheckersSettingsActivity extends Settings { /* empty */ }
641    public static class LocalePickerActivity extends Settings { /* empty */ }
642    public static class UserDictionarySettingsActivity extends Settings { /* empty */ }
643    public static class SoundSettingsActivity extends Settings { /* empty */ }
644    public static class DisplaySettingsActivity extends Settings { /* empty */ }
645    public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
646    public static class ApplicationSettingsActivity extends Settings { /* empty */ }
647    public static class ManageApplicationsActivity extends Settings { /* empty */ }
648    public static class StorageUseActivity extends Settings { /* empty */ }
649    public static class DevelopmentSettingsActivity extends Settings { /* empty */ }
650    public static class AccessibilitySettingsActivity extends Settings { /* empty */ }
651    public static class SecuritySettingsActivity extends Settings { /* empty */ }
652    public static class LocationSettingsActivity extends Settings { /* empty */ }
653    public static class PrivacySettingsActivity extends Settings { /* empty */ }
654    public static class DockSettingsActivity extends Settings { /* empty */ }
655    public static class RunningServicesActivity extends Settings { /* empty */ }
656    public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }
657    public static class PowerUsageSummaryActivity extends Settings { /* empty */ }
658    public static class AccountSyncSettingsActivity extends Settings { /* empty */ }
659    public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }
660    public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }
661    public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }
662    public static class DataUsageSummaryActivity extends Settings { /* empty */ }
663    public static class AdvancedWifiSettingsActivity extends Settings { /* empty */ }
664    public static class TextToSpeechSettingsActivity extends Settings { /* empty */ }
665    public static class AndroidBeamSettingsActivity extends Settings { /* empty */ }
666}
667