From d4c7b497fb9ed220b06400a7738313d33cd91d61 Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Tue, 11 Jun 2013 21:15:11 -0700 Subject: [PATCH] Print - Settings Change-Id: Id662a41fb189823c6d06aafc7e98996f3ef6c930 --- res/values/strings.xml | 37 +- res/xml/print_settings.xml | 26 + res/xml/settings_headers.xml | 7 + .../settings/AccessibilitySettings.java | 4 +- .../android/settings/PrintingSettings.java | 587 ++++++++++++++++++ src/com/android/settings/Settings.java | 3 +- 6 files changed, 657 insertions(+), 7 deletions(-) create mode 100644 res/xml/print_settings.xml create mode 100644 src/com/android/settings/PrintingSettings.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 068bdb9516b..87b191167cd 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -3189,10 +3189,10 @@ Settings - - On - - Off + + On + + Off @@ -3232,6 +3232,35 @@ Settings + + + + + Printing + + Printing settings + + Services + + + Use + %1$s? + + + %1$s can receive documents you print. + Such documents may contain sensitive data. + + + No services installed + + + Settings + + + Add printers + diff --git a/res/xml/print_settings.xml b/res/xml/print_settings.xml new file mode 100644 index 00000000000..b21f2ac2a27 --- /dev/null +++ b/res/xml/print_settings.xml @@ -0,0 +1,26 @@ + + + + + + + + + diff --git a/res/xml/settings_headers.xml b/res/xml/settings_headers.xml index 05fa31f3d90..e809fb90858 100644 --- a/res/xml/settings_headers.xml +++ b/res/xml/settings_headers.xml @@ -175,6 +175,13 @@ android:icon="@drawable/ic_settings_accessibility" android:title="@string/accessibility_settings" /> + +
+
sInstalledServicesList = new ArrayList(); + + private static final Set sEnabledServiceNameSet = new HashSet(); + + 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.feature_state_on)); + } else { + preference.setSummary(getString(R.string.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 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 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 891a0c40163..51e1a959953 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -122,7 +122,8 @@ public class Settings extends PreferenceActivity R.id.system_section, R.id.date_time_settings, R.id.about_settings, - R.id.accessibility_settings + R.id.accessibility_settings, + R.id.print_settings }; private SharedPreferences mDevelopmentPreferences;