Implementing print settings as per UX spec.

Change-Id: Iafe99a1e959472f893cf168d952d9dd19ff160c0
diff --git a/src/com/android/settings/PrintingSettings.java b/src/com/android/settings/PrintingSettings.java
deleted file mode 100644
index 723bdc9..0000000
--- a/src/com/android/settings/PrintingSettings.java
+++ /dev/null
@@ -1,587 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings;
-
-import android.app.ActionBar;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.preference.Preference;
-import android.preference.PreferenceActivity;
-import android.preference.PreferenceCategory;
-import android.preference.PreferenceScreen;
-import android.printservice.PrintServiceInfo;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.text.TextUtils.SimpleStringSplitter;
-import android.view.Gravity;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import com.android.internal.content.PackageMonitor;
-import com.android.settings.PrintingSettings.ToggleSwitch.OnBeforeCheckedChangeListener;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Activity with the printing settings.
- */
-public class PrintingSettings extends SettingsPreferenceFragment implements DialogCreatable {
-
-    private static final char ENABLED_PRINT_SERVICES_SEPARATOR = ':';
-
-    // Preference categories
-    private static final String SERVICES_CATEGORY = "services_category";
-
-    // Extras passed to sub-fragments.
-    private static final String EXTRA_PREFERENCE_KEY = "preference_key";
-    private static final String EXTRA_CHECKED = "checked";
-    private static final String EXTRA_TITLE = "title";
-    private static final String EXTRA_ENABLE_WARNING_TITLE = "enable_warning_title";
-    private static final String EXTRA_ENABLE_WARNING_MESSAGE = "enable_warning_message";
-    private static final String EXTRA_SETTINGS_TITLE = "settings_title";
-    private static final String EXTRA_SETTINGS_COMPONENT_NAME = "settings_component_name";
-    private static final String EXTRA_ADD_PRINTERS_TITLE = "add_printers_title";
-    private static final String EXTRA_ADD_PRINTERS_COMPONENT_NAME = "add_printers_component_name";
-    private static final String EXTRA_SERVICE_COMPONENT_NAME = "service_component_name";
-
-    // Auxiliary members.
-    private final static SimpleStringSplitter sStringColonSplitter =
-            new SimpleStringSplitter(ENABLED_PRINT_SERVICES_SEPARATOR);
-
-    private static final List<ResolveInfo> sInstalledServicesList = new ArrayList<ResolveInfo>();
-
-    private static final Set<ComponentName> sEnabledServiceNameSet = new HashSet<ComponentName>();
-
-    private final PackageMonitor mSettingsPackageMonitor = new SettingsPackageMonitor();
-
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void dispatchMessage(Message msg) {
-            super.dispatchMessage(msg);
-            loadInstalledServices(getActivity());
-            loadEnabledServices(getActivity());
-            updateServicesPreferences();
-        }
-    };
-
-    private final SettingsContentObserver mSettingsContentObserver =
-            new SettingsContentObserver(mHandler) {
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            loadInstalledServices(getActivity());
-            loadEnabledServices(getActivity());
-            updateServicesPreferences();
-        }
-    };
-
-    // Preference controls.
-    private PreferenceCategory mServicesCategory;
-
-    private Preference mNoServicesMessagePreference;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        addPreferencesFromResource(R.xml.print_settings);
-        mServicesCategory = (PreferenceCategory) findPreference(SERVICES_CATEGORY);
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        mSettingsPackageMonitor.register(getActivity(), getActivity().getMainLooper(), false);
-        mSettingsContentObserver.register(getContentResolver());
-        loadInstalledServices(getActivity());
-        loadEnabledServices(getActivity());
-        updateServicesPreferences();
-    }
-
-    @Override
-    public void onPause() {
-        mSettingsPackageMonitor.unregister();
-        mSettingsContentObserver.unregister(getContentResolver());
-        super.onPause();
-    }
-
-    private void updateServicesPreferences() {
-        // Since services category is auto generated we have to do a pass
-        // to generate it since services can come and go.
-        mServicesCategory.removeAll();
-
-       final int installedServiceCount = sInstalledServicesList.size();
-        for (int i = 0; i < installedServiceCount; i++) {
-            ResolveInfo installedService = sInstalledServicesList.get(i);
-
-            PreferenceScreen preference = getPreferenceManager().createPreferenceScreen(
-                    getActivity());
-
-            String title = installedService.loadLabel(getPackageManager()).toString();
-            preference.setTitle(title);
-
-            ComponentName componentName = new ComponentName(
-                    installedService.serviceInfo.packageName,
-                    installedService.serviceInfo.name);
-            preference.setKey(componentName.flattenToString());
-
-            final boolean serviceEnabled = sEnabledServiceNameSet.contains(componentName);
-            if (serviceEnabled) {
-                preference.setSummary(getString(R.string.print_feature_state_on));
-            } else {
-                preference.setSummary(getString(R.string.print_feature_state_off));
-            }
-
-            preference.setOrder(i);
-            preference.setFragment(TogglePrintServicePreferenceFragment.class.getName());
-            preference.setPersistent(false);
-
-            Bundle extras = preference.getExtras();
-            extras.putString(EXTRA_PREFERENCE_KEY, preference.getKey());
-            extras.putBoolean(EXTRA_CHECKED, serviceEnabled);
-            extras.putString(EXTRA_TITLE, title);
-
-            PrintServiceInfo printServiceInfo = PrintServiceInfo.create(
-                    installedService, getActivity());
-
-            CharSequence applicationLabel = installedService.loadLabel(getPackageManager());
-
-            extras.putString(EXTRA_ENABLE_WARNING_TITLE, getString(
-                    R.string.print_service_security_warning_title, applicationLabel));
-            extras.putString(EXTRA_ENABLE_WARNING_MESSAGE, getString(
-                    R.string.print_service_security_warning_summary, applicationLabel));
-
-            String settingsClassName = printServiceInfo.getSettingsActivityName();
-            if (!TextUtils.isEmpty(settingsClassName)) {
-                extras.putString(EXTRA_SETTINGS_TITLE,
-                        getString(R.string.print_menu_item_settings));
-                extras.putString(EXTRA_SETTINGS_COMPONENT_NAME,
-                        new ComponentName(installedService.serviceInfo.packageName,
-                                settingsClassName).flattenToString());
-            }
-
-            String addPrinterClassName = printServiceInfo.getAddPrintersActivityName();
-            if (!TextUtils.isEmpty(addPrinterClassName)) {
-                extras.putString(EXTRA_ADD_PRINTERS_TITLE,
-                        getString(R.string.print_menu_item_add_printers));
-                extras.putString(EXTRA_ADD_PRINTERS_COMPONENT_NAME,
-                        new ComponentName(installedService.serviceInfo.packageName,
-                                addPrinterClassName).flattenToString());
-            }
-
-            extras.putString(EXTRA_SERVICE_COMPONENT_NAME, componentName.flattenToString());
-
-            mServicesCategory.addPreference(preference);
-        }
-
-        if (mServicesCategory.getPreferenceCount() == 0) {
-            if (mNoServicesMessagePreference == null) {
-                mNoServicesMessagePreference = new Preference(getActivity()) {
-                    @Override
-                    protected void onBindView(View view) {
-                        super.onBindView(view);
-                        TextView summaryView = (TextView) view.findViewById(R.id.summary);
-                        String title = getString(R.string.print_no_services_installed);
-                        summaryView.setText(title);
-                    }
-                };
-                mNoServicesMessagePreference.setPersistent(false);
-                mNoServicesMessagePreference.setLayoutResource(
-                        R.layout.text_description_preference);
-                mNoServicesMessagePreference.setSelectable(false);
-            }
-            mServicesCategory.addPreference(mNoServicesMessagePreference);
-        }
-    }
-
-    private static void loadInstalledServices(Context context) {
-        sInstalledServicesList.clear();
-        List<ResolveInfo> resolveInfos = context.getPackageManager().queryIntentServices(
-                    new Intent(android.printservice.PrintService.SERVICE_INTERFACE),
-                    PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
-        final int resolveInfoCount = resolveInfos.size();
-        for (int i = 0, count = resolveInfoCount; i < count; i++) {
-            ResolveInfo resolveInfo = resolveInfos.get(i);
-            sInstalledServicesList.add(resolveInfo);
-        }
-    }
-
-    private static void loadEnabledServices(Context context) {
-        sEnabledServiceNameSet.clear();
-
-        String enabledServicesSetting = Settings.Secure.getString(context
-                .getContentResolver(), Settings.Secure.ENABLED_PRINT_SERVICES);
-        if (enabledServicesSetting == null) {
-            enabledServicesSetting = "";
-        }
-
-        SimpleStringSplitter colonSplitter = sStringColonSplitter;
-        colonSplitter.setString(enabledServicesSetting);
-
-        while (colonSplitter.hasNext()) {
-            String componentNameString = colonSplitter.next();
-            ComponentName enabledService = ComponentName.unflattenFromString(
-                    componentNameString);
-            sEnabledServiceNameSet.add(enabledService);
-        }
-    }
-
-    private class SettingsPackageMonitor extends PackageMonitor {
-        @Override
-        public void onPackageAdded(String packageName, int uid) {
-           mHandler.obtainMessage().sendToTarget();
-        }
-
-        @Override
-        public void onPackageAppeared(String packageName, int reason) {
-            mHandler.obtainMessage().sendToTarget();
-        }
-
-        @Override
-        public void onPackageDisappeared(String packageName, int reason) {
-            mHandler.obtainMessage().sendToTarget();
-        }
-
-        @Override
-        public void onPackageRemoved(String packageName, int uid) {
-            mHandler.obtainMessage().sendToTarget();
-        }
-    }
-
-    public static class ToggleSwitch extends Switch {
-
-        private OnBeforeCheckedChangeListener mOnBeforeListener;
-
-        public static interface OnBeforeCheckedChangeListener {
-            public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked);
-        }
-
-        public ToggleSwitch(Context context) {
-            super(context);
-        }
-
-        public void setOnBeforeCheckedChangeListener(OnBeforeCheckedChangeListener listener) {
-            mOnBeforeListener = listener;
-        }
-
-        @Override
-        public void setChecked(boolean checked) {
-            if (mOnBeforeListener != null
-                    && mOnBeforeListener.onBeforeCheckedChanged(this, checked)) {
-                return;
-            }
-            super.setChecked(checked);
-        }
-
-        public void setCheckedInternal(boolean checked) {
-            super.setChecked(checked);
-        }
-    }
-
-    public static class TogglePrintServicePreferenceFragment
-            extends ToggleFeaturePreferenceFragment implements DialogInterface.OnClickListener {
-
-        private static final int DIALOG_ID_ENABLE_WARNING = 1;
-
-        private final SettingsContentObserver mSettingsContentObserver =
-                new SettingsContentObserver(new Handler()) {
-            @Override
-            public void onChange(boolean selfChange, Uri uri) {
-                String settingValue = Settings.Secure.getString(getContentResolver(),
-                        Settings.Secure.ENABLED_PRINT_SERVICES);
-                final boolean enabled = settingValue.contains(mComponentName);
-                mToggleSwitch.setCheckedInternal(enabled);
-            }
-        };
-
-        private CharSequence mEnableWarningTitle;
-        private CharSequence mEnableWarningMessage;
-
-        private String mComponentName;
-
-        @Override
-        public void onResume() {
-            mSettingsContentObserver.register(getContentResolver());
-            super.onResume();
-        }
-
-        @Override
-        public void onPause() {
-            mSettingsContentObserver.unregister(getContentResolver());
-            super.onPause();
-        }
-
-        @Override
-        public void onPreferenceToggled(String preferenceKey, boolean enabled) {
-            Set<ComponentName> enabledServices = sEnabledServiceNameSet;
-            ComponentName toggledService = ComponentName.unflattenFromString(preferenceKey);
-            if (enabled) {
-                enabledServices.add(toggledService);
-            } else {
-                enabledServices.remove(toggledService);
-            }
-            StringBuilder enabledServicesBuilder = new StringBuilder();
-            for (ComponentName enabledService : enabledServices) {
-                enabledServicesBuilder.append(enabledService.flattenToString());
-                enabledServicesBuilder.append(ENABLED_PRINT_SERVICES_SEPARATOR);
-            }
-            final int enabledServicesBuilderLength = enabledServicesBuilder.length();
-            if (enabledServicesBuilderLength > 0) {
-                enabledServicesBuilder.deleteCharAt(enabledServicesBuilderLength - 1);
-            }
-            Settings.Secure.putString(getContentResolver(),
-                    Settings.Secure.ENABLED_PRINT_SERVICES,
-                    enabledServicesBuilder.toString());
-        }
-
-        @Override
-        public Dialog onCreateDialog(int dialogId) {
-            CharSequence title = null;
-            CharSequence message = null;
-            switch (dialogId) {
-                case DIALOG_ID_ENABLE_WARNING:
-                    title = mEnableWarningTitle;
-                    message = mEnableWarningMessage;
-                    break;
-                default:
-                    throw new IllegalArgumentException();
-            }
-            return new AlertDialog.Builder(getActivity())
-                    .setTitle(title)
-                    .setIconAttribute(android.R.attr.alertDialogIcon)
-                    .setMessage(message)
-                    .setCancelable(true)
-                    .setPositiveButton(android.R.string.ok, this)
-                    .setNegativeButton(android.R.string.cancel, this)
-                    .create();
-        }
-
-        @Override
-        public void onClick(DialogInterface dialog, int which) {
-            final boolean checked;
-            switch (which) {
-                case DialogInterface.BUTTON_POSITIVE:
-                    checked = true;
-                    mToggleSwitch.setCheckedInternal(checked);
-                    getArguments().putBoolean(EXTRA_CHECKED, checked);
-                    onPreferenceToggled(mPreferenceKey, checked);
-                    break;
-                case DialogInterface.BUTTON_NEGATIVE:
-                    checked = false;
-                    mToggleSwitch.setCheckedInternal(checked);
-                    getArguments().putBoolean(EXTRA_CHECKED, checked);
-                    onPreferenceToggled(mPreferenceKey, checked);
-                    break;
-                default:
-                    throw new IllegalArgumentException();
-            }
-        }
-
-        @Override
-        protected void onInstallActionBarToggleSwitch() {
-            super.onInstallActionBarToggleSwitch();
-            mToggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
-                @Override
-                public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
-                    if (checked) {
-                        if (!TextUtils.isEmpty(mEnableWarningMessage)) {
-                            toggleSwitch.setCheckedInternal(false);
-                            getArguments().putBoolean(EXTRA_CHECKED, false);
-                            showDialog(DIALOG_ID_ENABLE_WARNING);
-                            return true;
-                        }
-                        onPreferenceToggled(mPreferenceKey, true);
-                    } else {
-                        onPreferenceToggled(mPreferenceKey, false);
-                    }
-                    return false;
-                }
-            });
-        }
-
-        @Override
-        protected void onProcessArguments(Bundle arguments) {
-            super.onProcessArguments(arguments);
-            // Settings title and intent.
-            String settingsTitle = arguments.getString(EXTRA_SETTINGS_TITLE);
-            String settingsComponentName = arguments.getString(EXTRA_SETTINGS_COMPONENT_NAME);
-            if (!TextUtils.isEmpty(settingsTitle) && !TextUtils.isEmpty(settingsComponentName)) {
-                Intent settingsIntent = new Intent(Intent.ACTION_MAIN).setComponent(
-                        ComponentName.unflattenFromString(settingsComponentName.toString()));
-                if (!getPackageManager().queryIntentActivities(settingsIntent, 0).isEmpty()) {
-                    mSettingsTitle = settingsTitle;
-                    mSettingsIntent = settingsIntent;
-                    setHasOptionsMenu(true);
-                }
-            }
-            // Add printers title and intent.
-            String addPrintersTitle = arguments.getString(EXTRA_ADD_PRINTERS_TITLE);
-            String addPrintersComponentName =
-                    arguments.getString(EXTRA_ADD_PRINTERS_COMPONENT_NAME);
-            if (!TextUtils.isEmpty(addPrintersTitle)
-                    && !TextUtils.isEmpty(addPrintersComponentName)) {
-                Intent addPritnersIntent = new Intent(Intent.ACTION_MAIN).setComponent(
-                        ComponentName.unflattenFromString(addPrintersComponentName.toString()));
-                if (!getPackageManager().queryIntentActivities(addPritnersIntent, 0).isEmpty()) {
-                    mAddPrintersTitle = addPrintersTitle;
-                    mAddPrintersIntent = addPritnersIntent;
-                    setHasOptionsMenu(true);
-                }
-            }
-            // Enable warning title.
-            mEnableWarningTitle = arguments.getCharSequence(
-                    PrintingSettings.EXTRA_ENABLE_WARNING_TITLE);
-            // Enable warning message.
-            mEnableWarningMessage = arguments.getCharSequence(
-                    PrintingSettings.EXTRA_ENABLE_WARNING_MESSAGE);
-            // Component name.
-            mComponentName = arguments.getString(EXTRA_SERVICE_COMPONENT_NAME);
-        }
-    }
-
-    public static abstract class ToggleFeaturePreferenceFragment
-            extends SettingsPreferenceFragment {
-
-        protected ToggleSwitch mToggleSwitch;
-
-        protected String mPreferenceKey;
-
-        protected CharSequence mSettingsTitle;
-        protected Intent mSettingsIntent;
-
-        protected CharSequence mAddPrintersTitle;
-        protected Intent mAddPrintersIntent;
-
-        // TODO: Showing sub-sub fragment does not handle the activity title
-        // so we do it but this is wrong. Do a real fix when there is time.
-        private CharSequence mOldActivityTitle;
-
-        @Override
-        public void onCreate(Bundle savedInstanceState) {
-            super.onCreate(savedInstanceState);
-            PreferenceScreen preferenceScreen = getPreferenceManager().createPreferenceScreen(
-                    getActivity());
-            setPreferenceScreen(preferenceScreen);
-        }
-
-        @Override
-        public void onViewCreated(View view, Bundle savedInstanceState) {
-            super.onViewCreated(view, savedInstanceState);
-            onInstallActionBarToggleSwitch();
-            onProcessArguments(getArguments());
-            getListView().setDivider(null);
-            getListView().setEnabled(false);
-        }
-
-        @Override
-        public void onDestroyView() {
-            getActivity().getActionBar().setCustomView(null);
-            if (mOldActivityTitle != null) {
-                getActivity().getActionBar().setTitle(mOldActivityTitle);
-            }
-            mToggleSwitch.setOnBeforeCheckedChangeListener(null);
-            super.onDestroyView();
-        }
-
-        protected abstract void onPreferenceToggled(String preferenceKey, boolean enabled);
-
-        @Override
-        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-            super.onCreateOptionsMenu(menu, inflater);
-            if (!TextUtils.isEmpty(mSettingsTitle) && mSettingsIntent != null) {
-                MenuItem menuItem = menu.add(mSettingsTitle);
-                menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
-                menuItem.setIntent(mSettingsIntent);
-            }
-            if (!TextUtils.isEmpty(mAddPrintersTitle) && mAddPrintersIntent != null) {
-                MenuItem menuItem = menu.add(mAddPrintersTitle);
-                menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
-                menuItem.setIntent(mAddPrintersIntent);
-            }
-        }
-
-        protected void onInstallActionBarToggleSwitch() {
-            mToggleSwitch = createAndAddActionBarToggleSwitch(getActivity());
-        }
-
-        private ToggleSwitch createAndAddActionBarToggleSwitch(Activity activity) {
-            ToggleSwitch toggleSwitch = new ToggleSwitch(activity);
-            final int padding = activity.getResources().getDimensionPixelSize(
-                    R.dimen.action_bar_switch_padding);
-            toggleSwitch.setPaddingRelative(0, 0, padding, 0);
-            activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
-                    ActionBar.DISPLAY_SHOW_CUSTOM);
-            activity.getActionBar().setCustomView(toggleSwitch,
-                    new ActionBar.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT,
-                            ActionBar.LayoutParams.WRAP_CONTENT,
-                            Gravity.CENTER_VERTICAL | Gravity.END));
-            return toggleSwitch;
-        }
-
-        protected void onProcessArguments(Bundle arguments) {
-            // Key.
-            mPreferenceKey = arguments.getString(EXTRA_PREFERENCE_KEY);
-            // Enabled.
-            final boolean enabled = arguments.getBoolean(EXTRA_CHECKED);
-            mToggleSwitch.setCheckedInternal(enabled);
-            // Title.
-            PreferenceActivity activity = (PreferenceActivity) getActivity();
-            if (!activity.onIsMultiPane() || activity.onIsHidingHeaders()) {
-                mOldActivityTitle = getActivity().getTitle();
-                String title = arguments.getString(EXTRA_TITLE);
-                getActivity().getActionBar().setTitle(title);
-            }
-        }
-    }
-
-    private static abstract class SettingsContentObserver extends ContentObserver {
-
-        public SettingsContentObserver(Handler handler) {
-            super(handler);
-        }
-
-        public void register(ContentResolver contentResolver) {
-            contentResolver.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ENABLED_PRINT_SERVICES), false, this);
-        }
-
-        public void unregister(ContentResolver contentResolver) {
-            contentResolver.unregisterContentObserver(this);
-        }
-
-        @Override
-        public abstract void onChange(boolean selfChange, Uri uri);
-    }
-}
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index a58d2b7..35fe885 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -19,13 +19,11 @@
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.OnAccountsUpdateListener;
-import android.app.Fragment;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.RestrictionEntry;
 import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
@@ -56,9 +54,6 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.settings.accessibility.AccessibilitySettings;
 import com.android.settings.accessibility.ToggleAccessibilityServicePreferenceFragment;
-import com.android.settings.ChooseLockGeneric.ChooseLockGenericFragment;
-import com.android.settings.ChooseLockPassword.ChooseLockPasswordFragment;
-import com.android.settings.ChooseLockPattern.ChooseLockPatternFragment;
 import com.android.settings.accounts.AccountSyncSettings;
 import com.android.settings.accounts.AuthenticatorHelper;
 import com.android.settings.accounts.ManageAccountsSettings;
@@ -76,8 +71,9 @@
 import com.android.settings.location.LocationSettings;
 import com.android.settings.nfc.AndroidBeam;
 import com.android.settings.nfc.PaymentSettings;
+import com.android.settings.print.PrintServiceSettingsFragment;
+import com.android.settings.print.PrintSettingsFragment;
 import com.android.settings.tts.TextToSpeechSettings;
-import com.android.settings.users.AppRestrictionsFragment;
 import com.android.settings.users.UserSettings;
 import com.android.settings.vpn2.VpnSettings;
 import com.android.settings.wfd.WifiDisplaySettings;
@@ -334,7 +330,7 @@
         UserSettings.class.getName(),
         NotificationAccessSettings.class.getName(),
         ManageAccountsSettings.class.getName(),
-        PrintingSettings.class.getName(),
+        PrintSettingsFragment.class.getName(),
         TrustedCredentialsSettings.class.getName(),
         PaymentSettings.class.getName()
     };
@@ -495,7 +491,9 @@
                 BluetoothSettings.class.getName().equals(fragmentName) ||
                 DreamSettings.class.getName().equals(fragmentName) ||
                 LocationSettings.class.getName().equals(fragmentName) ||
-                ToggleAccessibilityServicePreferenceFragment.class.getName().equals(fragmentName)) {
+                ToggleAccessibilityServicePreferenceFragment.class.getName().equals(fragmentName) ||
+                PrintSettingsFragment.class.getName().equals(fragmentName) ||
+                PrintServiceSettingsFragment.class.getName().equals(fragmentName)) {
             intent.putExtra(EXTRA_UI_OPTIONS, ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW);
         }
 
diff --git a/src/com/android/settings/print/PrintServiceSettingsFragment.java b/src/com/android/settings/print/PrintServiceSettingsFragment.java
new file mode 100644
index 0000000..c65e43e
--- /dev/null
+++ b/src/com/android/settings/print/PrintServiceSettingsFragment.java
@@ -0,0 +1,519 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.print;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.LoaderManager;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.Loader;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.preference.PreferenceActivity;
+import android.print.PrintManager;
+import android.print.PrinterDiscoverySession;
+import android.print.PrinterDiscoverySession.OnPrintersChangeListener;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.print.PrintSettingsFragment.ToggleSwitch;
+import com.android.settings.print.PrintSettingsFragment.ToggleSwitch.OnBeforeCheckedChangeListener;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Fragment with print service settings.
+ */
+public class PrintServiceSettingsFragment extends SettingsPreferenceFragment
+        implements DialogInterface.OnClickListener {
+
+    private static final int LOADER_ID_PRINTERS_LOADER = 1;
+
+    private static final int DIALOG_ID_ENABLE_WARNING = 1;
+
+    private final SettingsContentObserver mSettingsContentObserver =
+            new SettingsContentObserver(new Handler()) {
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            List<ComponentName> services = SettingsUtils.readEnabledPrintServices(getActivity());
+            final boolean enabled = services.contains(mComponentName);
+            mToggleSwitch.setCheckedInternal(enabled);
+        }
+    };
+
+    protected ToggleSwitch mToggleSwitch;
+
+    protected String mPreferenceKey;
+
+    protected CharSequence mSettingsTitle;
+    protected Intent mSettingsIntent;
+
+    protected CharSequence mAddPrintersTitle;
+    protected Intent mAddPrintersIntent;
+
+    private CharSequence mEnableWarningTitle;
+    private CharSequence mEnableWarningMessage;
+
+    private ComponentName mComponentName;
+
+    // TODO: Showing sub-sub fragment does not handle the activity title
+    // so we do it but this is wrong. Do a real fix when there is time.
+    private CharSequence mOldActivityTitle;
+
+    @Override
+    public void onResume() {
+        mSettingsContentObserver.register(getContentResolver());
+        super.onResume();
+    }
+
+    @Override
+    public void onPause() {
+        mSettingsContentObserver.unregister(getContentResolver());
+        super.onPause();
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        onInstallActionBarToggleSwitch();
+        processArguments(getArguments());
+        getListView().setAdapter(new PrintersAdapter());
+    }
+
+    @Override
+    public void onDestroyView() {
+        getActivity().getActionBar().setCustomView(null);
+        if (mOldActivityTitle != null) {
+            getActivity().getActionBar().setTitle(mOldActivityTitle);
+        }
+        mToggleSwitch.setOnBeforeCheckedChangeListener(null);
+        super.onDestroyView();
+    }
+
+    private void onPreferenceToggled(String preferenceKey, boolean enabled) {
+        ComponentName service = ComponentName.unflattenFromString(preferenceKey);
+        List<ComponentName> services = SettingsUtils.readEnabledPrintServices(getActivity());
+        if (enabled) {
+            services.add(service);
+        } else {
+            services.remove(service);
+        }
+        SettingsUtils.writeEnabledPrintServices(getActivity(), services);
+    }
+
+    @Override
+    public Dialog onCreateDialog(int dialogId) {
+        CharSequence title = null;
+        CharSequence message = null;
+        switch (dialogId) {
+            case DIALOG_ID_ENABLE_WARNING:
+                title = mEnableWarningTitle;
+                message = mEnableWarningMessage;
+                break;
+            default:
+                throw new IllegalArgumentException();
+        }
+        return new AlertDialog.Builder(getActivity())
+                .setTitle(title)
+                .setIconAttribute(android.R.attr.alertDialogIcon)
+                .setMessage(message)
+                .setCancelable(true)
+                .setPositiveButton(android.R.string.ok, this)
+                .setNegativeButton(android.R.string.cancel, this)
+                .create();
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        final boolean checked;
+        switch (which) {
+            case DialogInterface.BUTTON_POSITIVE:
+                checked = true;
+                mToggleSwitch.setCheckedInternal(checked);
+                getArguments().putBoolean(PrintSettingsFragment.EXTRA_CHECKED, checked);
+                onPreferenceToggled(mPreferenceKey, checked);
+                break;
+            case DialogInterface.BUTTON_NEGATIVE:
+                checked = false;
+                mToggleSwitch.setCheckedInternal(checked);
+                getArguments().putBoolean(PrintSettingsFragment.EXTRA_CHECKED, checked);
+                onPreferenceToggled(mPreferenceKey, checked);
+                break;
+            default:
+                throw new IllegalArgumentException();
+        }
+    }
+
+    protected void onInstallActionBarToggleSwitch() {
+        mToggleSwitch = createAndAddActionBarToggleSwitch(getActivity());
+        mToggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
+            @Override
+            public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
+                if (checked) {
+                    if (!TextUtils.isEmpty(mEnableWarningMessage)) {
+                        toggleSwitch.setCheckedInternal(false);
+                        getArguments().putBoolean(PrintSettingsFragment.EXTRA_CHECKED, false);
+                        showDialog(DIALOG_ID_ENABLE_WARNING);
+                        return true;
+                    }
+                    onPreferenceToggled(mPreferenceKey, true);
+                } else {
+                    onPreferenceToggled(mPreferenceKey, false);
+                }
+                return false;
+            }
+        });
+    }
+
+    private void processArguments(Bundle arguments) {
+        // Key.
+        mPreferenceKey = arguments.getString(PrintSettingsFragment.EXTRA_PREFERENCE_KEY);
+
+        // Enabled.
+        final boolean enabled = arguments.getBoolean(PrintSettingsFragment.EXTRA_CHECKED);
+        mToggleSwitch.setCheckedInternal(enabled);
+
+        // Title.
+        PreferenceActivity activity = (PreferenceActivity) getActivity();
+        if (!activity.onIsMultiPane() || activity.onIsHidingHeaders()) {
+            mOldActivityTitle = getActivity().getTitle();
+            String title = arguments.getString(PrintSettingsFragment.EXTRA_TITLE);
+            getActivity().getActionBar().setTitle(title);
+        }
+
+        // Settings title and intent.
+        String settingsTitle = arguments.getString(PrintSettingsFragment.EXTRA_SETTINGS_TITLE);
+        String settingsComponentName = arguments.getString(
+                PrintSettingsFragment.EXTRA_SETTINGS_COMPONENT_NAME);
+        if (!TextUtils.isEmpty(settingsTitle) && !TextUtils.isEmpty(settingsComponentName)) {
+            Intent settingsIntent = new Intent(Intent.ACTION_MAIN).setComponent(
+                    ComponentName.unflattenFromString(settingsComponentName.toString()));
+            if (!getPackageManager().queryIntentActivities(settingsIntent, 0).isEmpty()) {
+                mSettingsTitle = settingsTitle;
+                mSettingsIntent = settingsIntent;
+                setHasOptionsMenu(true);
+            }
+        }
+
+        // Add printers title and intent.
+        String addPrintersTitle = arguments.getString(
+                PrintSettingsFragment.EXTRA_ADD_PRINTERS_TITLE);
+        String addPrintersComponentName =
+                arguments.getString(PrintSettingsFragment.EXTRA_ADD_PRINTERS_COMPONENT_NAME);
+        if (!TextUtils.isEmpty(addPrintersTitle)
+                && !TextUtils.isEmpty(addPrintersComponentName)) {
+            Intent addPritnersIntent = new Intent(Intent.ACTION_MAIN).setComponent(
+                    ComponentName.unflattenFromString(addPrintersComponentName.toString()));
+            if (!getPackageManager().queryIntentActivities(addPritnersIntent, 0).isEmpty()) {
+                mAddPrintersTitle = addPrintersTitle;
+                mAddPrintersIntent = addPritnersIntent;
+                setHasOptionsMenu(true);
+            }
+        }
+
+        // Enable warning title.
+        mEnableWarningTitle = arguments.getCharSequence(
+                PrintSettingsFragment.EXTRA_ENABLE_WARNING_TITLE);
+
+        // Enable warning message.
+        mEnableWarningMessage = arguments.getCharSequence(
+                PrintSettingsFragment.EXTRA_ENABLE_WARNING_MESSAGE);
+
+        // Component name.
+        mComponentName = ComponentName.unflattenFromString(arguments
+                .getString(PrintSettingsFragment.EXTRA_SERVICE_COMPONENT_NAME));
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        super.onCreateOptionsMenu(menu, inflater);
+        inflater.inflate(R.menu.print_service_settings, menu);
+
+        MenuItem addPrinters = menu.findItem(R.id.print_menu_item_add_printer);
+        if (!TextUtils.isEmpty(mAddPrintersTitle) && mAddPrintersIntent != null) {
+            addPrinters.setIntent(mAddPrintersIntent);
+        } else {
+            menu.removeItem(R.id.print_menu_item_add_printer);
+        }
+
+        MenuItem settings = menu.findItem(R.id.print_menu_item_settings);
+        if (!TextUtils.isEmpty(mSettingsTitle) && mSettingsIntent != null) {
+            settings.setIntent(mSettingsIntent);
+        } else {
+            menu.removeItem(R.id.print_menu_item_settings);
+        }
+
+        MenuItem uninstall = menu.findItem(R.id.print_menu_item_uninstall);
+        Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE,
+                Uri.parse("package:" + mComponentName.getPackageName()));
+        uninstall.setIntent(uninstallIntent);
+    }
+
+    private ToggleSwitch createAndAddActionBarToggleSwitch(Activity activity) {
+        ToggleSwitch toggleSwitch = new ToggleSwitch(activity);
+        final int padding = activity.getResources().getDimensionPixelSize(
+                R.dimen.action_bar_switch_padding);
+        toggleSwitch.setPaddingRelative(0, 0, padding, 0);
+        activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
+                ActionBar.DISPLAY_SHOW_CUSTOM);
+        activity.getActionBar().setCustomView(toggleSwitch,
+                new ActionBar.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT,
+                        ActionBar.LayoutParams.WRAP_CONTENT,
+                        Gravity.CENTER_VERTICAL | Gravity.END));
+        return toggleSwitch;
+    }
+
+    private static abstract class SettingsContentObserver extends ContentObserver {
+
+    public SettingsContentObserver(Handler handler) {
+        super(handler);
+    }
+
+    public void register(ContentResolver contentResolver) {
+        contentResolver.registerContentObserver(Settings.Secure.getUriFor(
+                Settings.Secure.ENABLED_PRINT_SERVICES), false, this);
+    }
+
+    public void unregister(ContentResolver contentResolver) {
+        contentResolver.unregisterContentObserver(this);
+    }
+
+    @Override
+    public abstract void onChange(boolean selfChange, Uri uri);
+
+    }
+
+    private final class PrintersAdapter extends BaseAdapter
+            implements LoaderManager.LoaderCallbacks<List<PrinterInfo>>{
+        private final List<PrinterInfo> mPrinters = new ArrayList<PrinterInfo>();
+
+        public PrintersAdapter() {
+            getLoaderManager().initLoader(LOADER_ID_PRINTERS_LOADER, null, this);
+        }
+
+        @Override
+        public int getCount() {
+            return mPrinters.size();
+        }
+
+        @Override
+        public Object getItem(int position) {
+            return mPrinters.get(position);
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (convertView == null) {
+                convertView = getActivity().getLayoutInflater().inflate(
+                        R.layout.preference, parent, false);
+            }
+
+            PrinterInfo printer = (PrinterInfo) getItem(position);
+            CharSequence title = printer.getName();
+            CharSequence subtitle = null;
+            try {
+                PackageInfo packageInfo = getPackageManager().getPackageInfo(
+                        printer.getId().getServiceName().getPackageName(), 0);
+                        subtitle = packageInfo.applicationInfo.loadLabel(getPackageManager());
+            } catch (NameNotFoundException nnfe) {
+                /* ignore */
+            }
+
+            TextView titleView = (TextView) convertView.findViewById(android.R.id.title);
+            titleView.setText(title);
+
+            TextView subtitleView = (TextView) convertView.findViewById(android.R.id.summary);
+            if (!TextUtils.isEmpty(subtitle)) {
+                subtitleView.setText(subtitle);
+                subtitleView.setVisibility(View.VISIBLE);
+            } else {
+                subtitleView.setText(null);
+                subtitleView.setVisibility(View.GONE);
+            }
+
+            return convertView;
+        }
+
+        @Override
+        public Loader<List<PrinterInfo>> onCreateLoader(int id, Bundle args) {
+            if (id == LOADER_ID_PRINTERS_LOADER) {
+                return new PrintersLoader(getActivity());
+            }
+            return null;
+        }
+
+        @Override
+        public void onLoadFinished(Loader<List<PrinterInfo>> loader,
+                List<PrinterInfo> printers) {
+            mPrinters.clear();
+            final int printerCount = printers.size();
+            for (int i = 0; i < printerCount; i++) {
+                PrinterInfo printer = printers.get(i);
+                if (printer.getId().getServiceName().equals(mComponentName)) {
+                    mPrinters.add(printer);
+                }
+            }
+            notifyDataSetChanged();
+        }
+
+        @Override
+        public void onLoaderReset(Loader<List<PrinterInfo>> loader) {
+            mPrinters.clear();
+            notifyDataSetInvalidated();
+        }
+    }
+
+    private static class PrintersLoader extends Loader<List<PrinterInfo>> {
+
+        private static final String LOG_TAG = "PrintersLoader";
+
+        private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+
+        private final Map<PrinterId, PrinterInfo> mPrinters =
+                new LinkedHashMap<PrinterId, PrinterInfo>();
+
+        private PrinterDiscoverySession mDiscoverySession;
+
+        public PrintersLoader(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void deliverResult(List<PrinterInfo> printers) {
+            if (isStarted()) {
+                super.deliverResult(printers);
+            }
+        }
+
+        @Override
+        protected void onStartLoading() {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "onStartLoading()");
+            }
+            // The contract is that if we already have a valid,
+            // result the we have to deliver it immediately.
+            if (!mPrinters.isEmpty()) {
+                deliverResult(new ArrayList<PrinterInfo>(mPrinters.values()));
+            }
+            // We want to start discovery at this point.
+            onForceLoad();
+        }
+
+        @Override
+        protected void onStopLoading() {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "onStopLoading()");
+            }
+            onCancelLoad();
+        }
+
+        @Override
+        protected void onForceLoad() {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "onForceLoad()");
+            }
+            loadInternal();
+        }
+
+        @Override
+        protected boolean onCancelLoad() {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "onCancelLoad()");
+            }
+            return cancelInternal();
+        }
+
+        @Override
+        protected void onReset() {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "onReset()");
+            }
+            onStopLoading();
+            mPrinters.clear();
+            if (mDiscoverySession != null) {
+                mDiscoverySession.destroy();
+                mDiscoverySession = null;
+            }
+        }
+
+        @Override
+        protected void onAbandon() {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "onAbandon()");
+            }
+            onStopLoading();
+        }
+
+        private boolean cancelInternal() {
+            if (mDiscoverySession != null
+                    && mDiscoverySession.isPrinterDiscoveryStarted()) {
+                mDiscoverySession.stopPrinterDiscovery();
+                return true;
+            }
+            return false;
+        }
+
+        private void loadInternal() {
+            if (mDiscoverySession == null) {
+                PrintManager printManager = (PrintManager) getContext()
+                        .getSystemService(Context.PRINT_SERVICE);
+                mDiscoverySession = printManager.createPrinterDiscoverySession();
+                mDiscoverySession.setOnPrintersChangeListener(new OnPrintersChangeListener() {
+                    @Override
+                    public void onPrintersChanged() {
+                        deliverResult(new ArrayList<PrinterInfo>(
+                                mDiscoverySession.getPrinters()));
+                    }
+                });
+            }
+            mDiscoverySession.startPrinterDisovery(null);
+        }
+    }
+}
+
diff --git a/src/com/android/settings/print/PrintSettingsFragment.java b/src/com/android/settings/print/PrintSettingsFragment.java
new file mode 100644
index 0000000..6e7f528
--- /dev/null
+++ b/src/com/android/settings/print/PrintSettingsFragment.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.print;
+
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.preference.Preference;
+import android.preference.PreferenceScreen;
+import android.printservice.PrintServiceInfo;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import com.android.internal.content.PackageMonitor;
+import com.android.settings.DialogCreatable;
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+
+import java.util.List;
+
+/**
+ * Fragment with the top level print settings.
+ */
+public class PrintSettingsFragment extends SettingsPreferenceFragment implements DialogCreatable {
+
+    static final char ENABLED_PRINT_SERVICES_SEPARATOR = ':';
+
+    // Extras passed to sub-fragments.
+    static final String EXTRA_PREFERENCE_KEY = "preference_key";
+    static final String EXTRA_CHECKED = "checked";
+    static final String EXTRA_TITLE = "title";
+    static final String EXTRA_ENABLE_WARNING_TITLE = "enable_warning_title";
+    static final String EXTRA_ENABLE_WARNING_MESSAGE = "enable_warning_message";
+    static final String EXTRA_SETTINGS_TITLE = "settings_title";
+    static final String EXTRA_SETTINGS_COMPONENT_NAME = "settings_component_name";
+    static final String EXTRA_ADD_PRINTERS_TITLE = "add_printers_title";
+    static final String EXTRA_ADD_PRINTERS_COMPONENT_NAME = "add_printers_component_name";
+    static final String EXTRA_SERVICE_COMPONENT_NAME = "service_component_name";
+
+    private final PackageMonitor mSettingsPackageMonitor = new SettingsPackageMonitor();
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void dispatchMessage(Message msg) {
+            updateServicesPreferences();
+        }
+    };
+
+    private final SettingsContentObserver mSettingsContentObserver =
+            new SettingsContentObserver(mHandler) {
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            updateServicesPreferences();
+        }
+    };
+
+    private Preference mNoServicesMessagePreference;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        addPreferencesFromResource(R.xml.print_settings);
+        getActivity().getActionBar().setTitle(R.string.print_settings_title);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        mSettingsPackageMonitor.register(getActivity(), getActivity().getMainLooper(), false);
+        mSettingsContentObserver.register(getContentResolver());
+        updateServicesPreferences();
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+    public void onPause() {
+        mSettingsPackageMonitor.unregister();
+        mSettingsContentObserver.unregister(getContentResolver());
+        super.onPause();
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        super.onCreateOptionsMenu(menu, inflater);
+        inflater.inflate(R.menu.print_settings, menu);
+        MenuItem menuItem = menu.findItem(R.id.print_menu_item_download_print_service);
+        menuItem.setIntent(new Intent(Intent.ACTION_VIEW,
+                Uri.parse(getString(R.string.download_print_service_query))));
+    }
+
+    private void updateServicesPreferences() {
+        // Since services category is auto generated we have to do a pass
+        // to generate it since services can come and go.
+        getPreferenceScreen().removeAll();
+
+        List<ComponentName> enabledServices = SettingsUtils
+                .readEnabledPrintServices(getActivity());
+
+        List<ResolveInfo> installedServices = getActivity().getPackageManager()
+                .queryIntentServices(
+                        new Intent(android.printservice.PrintService.SERVICE_INTERFACE),
+                        PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
+
+        final int installedServiceCount = installedServices.size();
+        for (int i = 0; i < installedServiceCount; i++) {
+            ResolveInfo installedService = installedServices.get(i);
+
+            PreferenceScreen preference = getPreferenceManager().createPreferenceScreen(
+                    getActivity());
+
+            String title = installedService.loadLabel(getPackageManager()).toString();
+            preference.setTitle(title);
+
+            ComponentName componentName = new ComponentName(
+                    installedService.serviceInfo.packageName,
+                    installedService.serviceInfo.name);
+            preference.setKey(componentName.flattenToString());
+
+            preference.setOrder(i);
+            preference.setFragment(PrintServiceSettingsFragment.class.getName());
+            preference.setPersistent(false);
+
+            final boolean serviceEnabled = enabledServices.contains(componentName);
+            if (serviceEnabled) {
+                preference.setSummary(getString(R.string.print_feature_state_on));
+            } else {
+                preference.setSummary(getString(R.string.print_feature_state_off));
+            }
+
+            Bundle extras = preference.getExtras();
+            extras.putString(EXTRA_PREFERENCE_KEY, preference.getKey());
+            extras.putBoolean(EXTRA_CHECKED, serviceEnabled);
+            extras.putString(EXTRA_TITLE, title);
+
+            PrintServiceInfo printServiceInfo = PrintServiceInfo.create(
+                    installedService, getActivity());
+
+            CharSequence applicationLabel = installedService.loadLabel(getPackageManager());
+
+            extras.putString(EXTRA_ENABLE_WARNING_TITLE, getString(
+                    R.string.print_service_security_warning_title, applicationLabel));
+            extras.putString(EXTRA_ENABLE_WARNING_MESSAGE, getString(
+                    R.string.print_service_security_warning_summary, applicationLabel));
+
+            String settingsClassName = printServiceInfo.getSettingsActivityName();
+            if (!TextUtils.isEmpty(settingsClassName)) {
+                extras.putString(EXTRA_SETTINGS_TITLE,
+                        getString(R.string.print_menu_item_settings));
+                extras.putString(EXTRA_SETTINGS_COMPONENT_NAME,
+                        new ComponentName(installedService.serviceInfo.packageName,
+                                settingsClassName).flattenToString());
+            }
+
+            String addPrinterClassName = printServiceInfo.getAddPrintersActivityName();
+            if (!TextUtils.isEmpty(addPrinterClassName)) {
+                extras.putString(EXTRA_ADD_PRINTERS_TITLE,
+                        getString(R.string.print_menu_item_add_printers));
+                extras.putString(EXTRA_ADD_PRINTERS_COMPONENT_NAME,
+                        new ComponentName(installedService.serviceInfo.packageName,
+                                addPrinterClassName).flattenToString());
+            }
+
+            extras.putString(EXTRA_SERVICE_COMPONENT_NAME, componentName.flattenToString());
+
+            getPreferenceScreen().addPreference(preference);
+        }
+
+        if (getPreferenceScreen().getPreferenceCount() == 0) {
+            if (mNoServicesMessagePreference == null) {
+                mNoServicesMessagePreference = new Preference(getActivity()) {
+                    @Override
+                    protected void onBindView(View view) {
+                        super.onBindView(view);
+                        TextView summaryView = (TextView) view.findViewById(R.id.summary);
+                        String title = getString(R.string.print_no_services_installed);
+                        summaryView.setText(title);
+                    }
+                };
+                mNoServicesMessagePreference.setPersistent(false);
+                mNoServicesMessagePreference.setLayoutResource(
+                        R.layout.text_description_preference);
+                mNoServicesMessagePreference.setSelectable(false);
+            }
+            getPreferenceScreen().addPreference(mNoServicesMessagePreference);
+        }
+    }
+
+    private class SettingsPackageMonitor extends PackageMonitor {
+        @Override
+        public void onPackageAdded(String packageName, int uid) {
+           mHandler.obtainMessage().sendToTarget();
+        }
+
+        @Override
+        public void onPackageAppeared(String packageName, int reason) {
+            mHandler.obtainMessage().sendToTarget();
+        }
+
+        @Override
+        public void onPackageDisappeared(String packageName, int reason) {
+            mHandler.obtainMessage().sendToTarget();
+        }
+
+        @Override
+        public void onPackageRemoved(String packageName, int uid) {
+            mHandler.obtainMessage().sendToTarget();
+        }
+    }
+
+    public static class ToggleSwitch extends Switch {
+
+        private OnBeforeCheckedChangeListener mOnBeforeListener;
+
+        public static interface OnBeforeCheckedChangeListener {
+            public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked);
+        }
+
+        public ToggleSwitch(Context context) {
+            super(context);
+        }
+
+        public void setOnBeforeCheckedChangeListener(OnBeforeCheckedChangeListener listener) {
+            mOnBeforeListener = listener;
+        }
+
+        @Override
+        public void setChecked(boolean checked) {
+            if (mOnBeforeListener != null
+                    && mOnBeforeListener.onBeforeCheckedChanged(this, checked)) {
+                return;
+            }
+            super.setChecked(checked);
+        }
+
+        public void setCheckedInternal(boolean checked) {
+            super.setChecked(checked);
+        }
+    }
+
+    private static abstract class SettingsContentObserver extends ContentObserver {
+
+        public SettingsContentObserver(Handler handler) {
+            super(handler);
+        }
+
+        public void register(ContentResolver contentResolver) {
+            contentResolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.ENABLED_PRINT_SERVICES), false, this);
+        }
+
+        public void unregister(ContentResolver contentResolver) {
+            contentResolver.unregisterContentObserver(this);
+        }
+
+        @Override
+        public abstract void onChange(boolean selfChange, Uri uri);
+    }
+}
diff --git a/src/com/android/settings/print/SettingsUtils.java b/src/com/android/settings/print/SettingsUtils.java
new file mode 100644
index 0000000..37827e6
--- /dev/null
+++ b/src/com/android/settings/print/SettingsUtils.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.print;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.provider.Settings;
+import android.text.TextUtils.SimpleStringSplitter;
+
+import java.util.ArrayList;import java.util.List;
+
+/**
+ * Helper methods for reading and writing to print settings.
+ */
+public class SettingsUtils {
+
+    private static final char ENABLED_PRINT_SERVICES_SEPARATOR = ':';
+
+    private SettingsUtils() {
+        /* do nothing */
+    }
+
+    public static List<ComponentName> readEnabledPrintServices(Context context) {
+        List<ComponentName> enabledServices = new ArrayList<ComponentName>();
+
+        String enabledServicesSetting = Settings.Secure.getString(context
+                .getContentResolver(), Settings.Secure.ENABLED_PRINT_SERVICES);
+        if (enabledServicesSetting == null) {
+            return enabledServices;
+        }
+
+        SimpleStringSplitter colonSplitter = new SimpleStringSplitter(
+                ENABLED_PRINT_SERVICES_SEPARATOR);
+        colonSplitter.setString(enabledServicesSetting);
+
+        while (colonSplitter.hasNext()) {
+            String componentNameString = colonSplitter.next();
+            ComponentName enabledService = ComponentName.unflattenFromString(
+                    componentNameString);
+            enabledServices.add(enabledService);
+        }
+
+        return enabledServices;
+    }
+
+    public static void writeEnabledPrintServices(Context context,
+            List<ComponentName> services) {
+        StringBuilder builder = new StringBuilder();
+        final int serviceCount = services.size();
+        for (int i = 0; i < serviceCount; i++) {
+            ComponentName service = services.get(i);
+            if (builder.length() > 0) {
+                builder.append(ENABLED_PRINT_SERVICES_SEPARATOR);
+            }
+            builder.append(service.flattenToString());
+        }
+        Settings.Secure.putString(context.getContentResolver(),
+                Settings.Secure.ENABLED_PRINT_SERVICES,
+                builder.toString());
+    }
+}