Files
app_Settings/src/com/android/settings/print/PrintSettingsFragment.java
Svetoslav 5c30529368 Remove Google Play specific search URIs from Settings.
1. If there are no installed print services or NFC payment services,
   we would like to allow the user to search for one in Play. However,
   Play is Google specific and we should not have hard coded URI that
   rely on it in settings. Declare secure settings for each of these
   URI and check at runtime if the URI is non-empty, then show the
   add menu item.

bug:11011519

Change-Id: I2c5cb172015bbecd7d2f8ffd3cb7fd790b01dab8
2013-09-30 15:59:46 -07:00

561 lines
22 KiB
Java

/*
* 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.ActivityManager;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.AsyncTaskLoader;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
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.PreferenceCategory;
import android.preference.PreferenceScreen;
import android.print.PrintJob;
import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.print.PrintManager.PrintJobStateChangeListener;
import android.printservice.PrintServiceInfo;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
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.text.DateFormat;
import java.util.ArrayList;
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 = ':';
private static final int LOADER_ID_PRINT_JOBS_LOADER = 1;
private static final String PRINT_JOBS_CATEGORY = "print_jobs_category";
private static final String PRINT_SERVICES_CATEGORY = "print_services_category";
// Extras passed to sub-fragments.
static final String EXTRA_PREFERENCE_KEY = "EXTRA_PREFERENCE_KEY";
static final String EXTRA_CHECKED = "EXTRA_CHECKED";
static final String EXTRA_TITLE = "EXTRA_TITLE";
static final String EXTRA_ENABLE_WARNING_TITLE = "EXTRA_ENABLE_WARNING_TITLE";
static final String EXTRA_ENABLE_WARNING_MESSAGE = "EXTRA_ENABLE_WARNING_MESSAGE";
static final String EXTRA_SETTINGS_TITLE = "EXTRA_SETTINGS_TITLE";
static final String EXTRA_SETTINGS_COMPONENT_NAME = "EXTRA_SETTINGS_COMPONENT_NAME";
static final String EXTRA_ADD_PRINTERS_TITLE = "EXTRA_ADD_PRINTERS_TITLE";
static final String EXTRA_ADD_PRINTERS_COMPONENT_NAME = "EXTRA_ADD_PRINTERS_COMPONENT_NAME";
static final String EXTRA_SERVICE_COMPONENT_NAME = "EXTRA_SERVICE_COMPONENT_NAME";
static final String EXTRA_PRINT_JOB_ID = "EXTRA_PRINT_JOB_ID";
private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME =
"EXTRA_PRINT_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 PreferenceCategory mActivePrintJobsCategory;
private PreferenceCategory mPrintServicesCategory;
private PrintJobsController mPrintJobsController;
private String mPrintJobPreferenceToActivate;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.print_settings);
mActivePrintJobsCategory = (PreferenceCategory) findPreference(
PRINT_JOBS_CATEGORY);
mPrintServicesCategory= (PreferenceCategory) findPreference(
PRINT_SERVICES_CATEGORY);
getPreferenceScreen().removePreference(mActivePrintJobsCategory);
mPrintJobsController = new PrintJobsController();
getActivity().getLoaderManager().initLoader(LOADER_ID_PRINT_JOBS_LOADER,
null, mPrintJobsController);
}
@Override
public void onResume() {
super.onResume();
mSettingsPackageMonitor.register(getActivity(), getActivity().getMainLooper(), false);
mSettingsContentObserver.register(getContentResolver());
updateServicesPreferences();
setHasOptionsMenu(true);
startSubSettingsIfNeeded();
}
@Override
public void onPause() {
mSettingsPackageMonitor.unregister();
mSettingsContentObserver.unregister(getContentResolver());
super.onPause();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
String searchUri = Settings.Secure.getString(getContentResolver(),
Settings.Secure.PRINT_SERVICE_SEARCH_URI);
if (!TextUtils.isEmpty(searchUri)) {
MenuItem menuItem = menu.add(R.string.print_menu_item_add_service);
menuItem.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menuItem.setIntent(new Intent(Intent.ACTION_VIEW,Uri.parse(searchUri)));
}
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ViewGroup contentRoot = (ViewGroup) getListView().getParent();
View emptyView = getActivity().getLayoutInflater().inflate(
R.layout.empty_print_state, contentRoot, false);
TextView textView = (TextView) emptyView.findViewById(R.id.message);
textView.setText(R.string.print_no_services_installed);
contentRoot.addView(emptyView);
getListView().setEmptyView(emptyView);
}
private void updateServicesPreferences() {
if (getPreferenceScreen().findPreference(PRINT_SERVICES_CATEGORY) == null) {
getPreferenceScreen().addPreference(mPrintServicesCategory);
} else {
// Since services category is auto generated we have to do a pass
// to generate it since services can come and go.
mPrintServicesCategory.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());
mPrintServicesCategory.addPreference(preference);
}
if (mPrintServicesCategory.getPreferenceCount() == 0) {
getPreferenceScreen().removePreference(mPrintServicesCategory);
}
}
private void startSubSettingsIfNeeded() {
if (getArguments() == null) {
return;
}
String componentName = getArguments().getString(EXTRA_PRINT_SERVICE_COMPONENT_NAME);
if (componentName != null) {
getArguments().remove(EXTRA_PRINT_SERVICE_COMPONENT_NAME);
Preference prereference = findPreference(componentName);
if (prereference != null) {
prereference.performClick(getPreferenceScreen());
}
} else {
String printJobId = getArguments().getString(EXTRA_PRINT_JOB_ID);
if (printJobId != null) {
getArguments().remove(EXTRA_PRINT_JOB_ID);
Preference preference = findPreference(printJobId);
if (preference != null) {
preference.performClick(getPreferenceScreen());
} else {
// The preference not being present may mean the the print job
// loader has not completed so make a note and wait for the load.
mPrintJobPreferenceToActivate = printJobId;
}
}
}
}
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);
}
private final class PrintJobsController implements LoaderCallbacks<List<PrintJobInfo>> {
@Override
public Loader<List<PrintJobInfo>> onCreateLoader(int id, Bundle args) {
if (id == LOADER_ID_PRINT_JOBS_LOADER) {
return new PrintJobsLoader(getActivity());
}
return null;
}
@Override
public void onLoadFinished(Loader<List<PrintJobInfo>> loader,
List<PrintJobInfo> printJobs) {
if (printJobs == null || printJobs.isEmpty()) {
getPreferenceScreen().removePreference(mActivePrintJobsCategory);
} else {
if (getPreferenceScreen().findPreference(PRINT_JOBS_CATEGORY) == null) {
getPreferenceScreen().addPreference(mActivePrintJobsCategory);
}
mActivePrintJobsCategory.removeAll();
final int printJobCount = printJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = printJobs.get(i);
PreferenceScreen preference = getPreferenceManager()
.createPreferenceScreen(getActivity());
preference.setPersistent(false);
preference.setFragment(PrintJobSettingsFragment.class.getName());
preference.setKey(printJob.getId().flattenToString());
switch (printJob.getState()) {
case PrintJobInfo.STATE_QUEUED:
case PrintJobInfo.STATE_STARTED: {
preference.setTitle(getString(
R.string.print_printing_state_title_template,
printJob.getLabel()));
} break;
case PrintJobInfo.STATE_FAILED: {
preference.setTitle(getString(
R.string.print_failed_state_title_template,
printJob.getLabel()));
} break;
case PrintJobInfo.STATE_BLOCKED: {
preference.setTitle(getString(
R.string.print_blocked_state_title_template,
printJob.getLabel()));
} break;
}
preference.setSummary(getString(R.string.print_job_summary,
printJob.getPrinterName(), DateUtils.formatSameDayTime(
printJob.getCreationTime(), printJob.getCreationTime(),
DateFormat.SHORT, DateFormat.SHORT)));
switch (printJob.getState()) {
case PrintJobInfo.STATE_QUEUED:
case PrintJobInfo.STATE_STARTED: {
preference.setIcon(com.android.internal.R.drawable.ic_print);
} break;
case PrintJobInfo.STATE_FAILED:
case PrintJobInfo.STATE_BLOCKED: {
preference.setIcon(com.android.internal.R.drawable.ic_print_error);
} break;
}
Bundle extras = preference.getExtras();
extras.putParcelable(EXTRA_PRINT_JOB_ID, printJob.getId());
mActivePrintJobsCategory.addPreference(preference);
}
// If were waiting for creating a preference for a print
// job so we can start it - do that.
if (mPrintJobPreferenceToActivate != null) {
Preference preference = findPreference(mPrintJobPreferenceToActivate);
mPrintJobPreferenceToActivate = null;
if (preference != null) {
preference.performClick(getPreferenceScreen());
}
}
}
}
@Override
public void onLoaderReset(Loader<List<PrintJobInfo>> loader) {
getPreferenceScreen().removePreference(mActivePrintJobsCategory);
}
}
private static final class PrintJobsLoader extends AsyncTaskLoader<List<PrintJobInfo>> {
private static final String LOG_TAG = "PrintJobsLoader";
private static final boolean DEBUG = true;
private List <PrintJobInfo> mPrintJobs = new ArrayList<PrintJobInfo>();
private final PrintManager mPrintManager;
private PrintJobStateChangeListener mPrintJobStateChangeListener;
public PrintJobsLoader(Context context) {
super(context);
mPrintManager = ((PrintManager) context.getSystemService(
Context.PRINT_SERVICE)).getGlobalPrintManagerForUser(
ActivityManager.getCurrentUser());
}
@Override
public void deliverResult(List<PrintJobInfo> printJobs) {
if (isStarted()) {
super.deliverResult(printJobs);
}
}
@Override
protected void onStartLoading() {
if (DEBUG) {
Log.i(LOG_TAG, "onStartLoading()");
}
// If we already have a result, deliver it immediately.
if (!mPrintJobs.isEmpty()) {
deliverResult(new ArrayList<PrintJobInfo>(mPrintJobs));
}
// Start watching for changes.
if (mPrintJobStateChangeListener == null) {
mPrintJobStateChangeListener = new PrintJobStateChangeListener() {
@Override
public void onPrintJobsStateChanged(PrintJobId printJobId) {
onForceLoad();
}
};
mPrintManager.addPrintJobStateChangeListener(
mPrintJobStateChangeListener);
}
// If the data changed or we have no data - load it now.
if (mPrintJobs.isEmpty()) {
onForceLoad();
}
}
@Override
protected void onStopLoading() {
if (DEBUG) {
Log.i(LOG_TAG, "onStopLoading()");
}
// Cancel the load in progress if possible.
onCancelLoad();
}
@Override
protected void onReset() {
if (DEBUG) {
Log.i(LOG_TAG, "onReset()");
}
// Stop loading.
onStopLoading();
// Clear the cached result.
mPrintJobs.clear();
// Stop watching for changes.
if (mPrintJobStateChangeListener != null) {
mPrintManager.removePrintJobStateChangeListener(
mPrintJobStateChangeListener);
mPrintJobStateChangeListener = null;
}
}
@Override
public List<PrintJobInfo> loadInBackground() {
List<PrintJobInfo> printJobInfos = null;
List<PrintJob> printJobs = mPrintManager.getPrintJobs();
final int printJobCount = printJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = printJobs.get(i).getInfo();
if (shouldShowToUser(printJob)) {
if (printJobInfos == null) {
printJobInfos = new ArrayList<PrintJobInfo>();
}
printJobInfos.add(printJob);
}
}
return printJobInfos;
}
private static boolean shouldShowToUser(PrintJobInfo printJob) {
switch (printJob.getState()) {
case PrintJobInfo.STATE_QUEUED:
case PrintJobInfo.STATE_STARTED:
case PrintJobInfo.STATE_BLOCKED:
case PrintJobInfo.STATE_FAILED: {
return true;
}
}
return false;
}
}
}