/* * Copyright (C) 2019 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.bips.ui; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceCategory; import android.preference.PreferenceFragment; import android.print.PrintManager; import android.printservice.recommendation.RecommendationInfo; import android.util.Log; import com.android.bips.R; import java.net.InetAddress; import java.text.Collator; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /** * A fragment allowing the user to review recommended print services and install or enable them. */ public class MoreOptionsFragment extends PreferenceFragment implements PrintManager.PrintServiceRecommendationsChangeListener { private static final String TAG = MoreOptionsFragment.class.getSimpleName(); private static final boolean DEBUG = false; private static final String KEY_RECOMMENDATION_CATEGORY = "recommendation_category"; private static final String KEY_MANAGE = "manage"; private static final String PACKAGE_NAME_VENDING = "com.android.vending"; private static final Collator COLLATOR = Collator.getInstance(); private PrintManager mPrintManager; private PackageManager mPackageManager; private PreferenceCategory mRecommendations; private MoreOptionsActivity mActivity; private boolean mHasVending = false; private Map mItems = new HashMap<>(); @Override public void onCreate(Bundle in) { super.onCreate(in); addPreferencesFromResource(R.xml.more_options_prefs); mRecommendations = (PreferenceCategory) getPreferenceScreen().findPreference( KEY_RECOMMENDATION_CATEGORY); getPreferenceScreen().findPreference(KEY_MANAGE) .setOnPreferenceClickListener(preference -> { startActivity(new Intent(android.provider.Settings.ACTION_PRINT_SETTINGS) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); return true; }); } @Override public void onStart() { super.onStart(); mPackageManager = getContext().getPackageManager(); try { // Attempt to get vending package, throws if missing mPackageManager.getPackageInfo(PACKAGE_NAME_VENDING, 0); mHasVending = true; } catch (PackageManager.NameNotFoundException ignored) { } mActivity = (MoreOptionsActivity) getActivity(); mPrintManager = getContext().getSystemService(PrintManager.class); // Start listening for recommendation changes mPrintManager.addPrintServiceRecommendationsChangeListener(this, null); onPrintServiceRecommendationsChanged(); } @Override public void onStop() { super.onStop(); mPrintManager.removePrintServiceRecommendationsChangeListener(this); } @Override public void onPrintServiceRecommendationsChanged() { List infos = mPrintManager.getPrintServiceRecommendations(); if (DEBUG) Log.d(TAG, "All recommendations count=" + infos.size()); // Update items list with new recommendations. Recommendations don't go away. for (RecommendationInfo info : infos) { for (InetAddress address : info.getDiscoveredPrinters()) { if (address.equals(mActivity.mPrinterAddress)) { // This recommendation matches so create or update an item for it String packageName = info.getPackageName().toString(); RecommendationItem item = getOrCreateItem(info); try { // If this doesn't throw then the service is installed item.mPrintService = mPackageManager.getPackageInfo(packageName, 0); } catch (PackageManager.NameNotFoundException e) { item.mPrintService = null; } break; } } } // Update preferences with ordering List itemList = new ArrayList<>(mItems.values()); Collections.sort(itemList); for (int index = 0; index < itemList.size(); index++) { itemList.get(index).updatePreference(index); } if (DEBUG) Log.d(TAG, "For this printer=" + mRecommendations.getPreferenceCount()); // Show group if not empty if (mRecommendations.getPreferenceCount() == 0) { getPreferenceScreen().removePreference(mRecommendations); } else { getPreferenceScreen().addPreference(mRecommendations); } } private RecommendationItem getOrCreateItem(RecommendationInfo recommendationInfo) { String packageName = recommendationInfo.getPackageName().toString(); RecommendationItem item = mItems.get(packageName); if (item == null) { item = new RecommendationItem(recommendationInfo); mItems.put(packageName, item); } else { item.mRecommendationInfo = recommendationInfo; } return item; } /** An item corresponding to a recommended print service. */ private class RecommendationItem implements Comparable { RecommendationInfo mRecommendationInfo; String mPackageName; Preference mPreference = new Preference(getContext()); /** Present only if the corresponding print service is installed. */ PackageInfo mPrintService; RecommendationItem(RecommendationInfo info) { mRecommendationInfo = info; mPackageName = mRecommendationInfo.getPackageName().toString(); } void updatePreference(int order) { mPreference.setKey(mPackageName); mPreference.setTitle(mRecommendationInfo.getName()); mPreference.setOrder(order); if (mPrintService != null) { updateEnabler(); if (mRecommendations.findPreference(mPackageName) == null) { mRecommendations.addPreference(mPreference); } } else if (mHasVending) { updateDownloader(); if (mRecommendations.findPreference(mPackageName) == null) { mRecommendations.addPreference(mPreference); } } else { mRecommendations.removePreference(mPreference); } } /** Update the preference to allow the user to enable an installed print service. */ private void updateEnabler() { try { // Set icon from application if possible mPreference.setIcon(mPackageManager.getApplicationIcon( mPrintService.packageName)); } catch (PackageManager.NameNotFoundException e) { mPreference.setIcon(null); mPreference.setIconSpaceReserved(true); } mPreference.setSummary(R.string.recommendation_enable_summary); mPreference.setOnPreferenceClickListener(preference -> { // There's no activity to go directly to the print service screen startActivity(new Intent(android.provider.Settings.ACTION_PRINT_SETTINGS) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); return true; }); } /** Update this preference to reflect a print service that must be downloaded. */ private void updateDownloader() { mPreference.setIcon(R.drawable.ic_download_from_market); mPreference.setSummary(R.string.recommendation_install_summary); mPreference.setOnPreferenceClickListener(preference -> { Uri printServiceUri = Uri.parse("market://details?id=" + mRecommendationInfo.getPackageName()); startActivity(new Intent(Intent.ACTION_VIEW, printServiceUri).setFlags( Intent.FLAG_ACTIVITY_NEW_TASK)); return true; }); } @Override public int compareTo(RecommendationItem other) { // Sort items: // - first by single-vendor (more likely to be manufacturer-specific), // - then alphabetically. if (mRecommendationInfo.recommendsMultiVendorService() != other.mRecommendationInfo.recommendsMultiVendorService()) { return mRecommendationInfo.recommendsMultiVendorService() ? 1 : -1; } return COLLATOR.compare(mRecommendationInfo.getName().toString(), other.mRecommendationInfo.getName().toString()); } } }