1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.car.settings.common; 18 19 import static com.android.settingslib.drawer.CategoryKey.CATEGORY_DEVICE; 20 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON; 21 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY; 22 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE; 23 24 import android.app.ActivityManager; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.pm.ActivityInfo; 28 import android.content.pm.PackageManager; 29 import android.content.pm.ResolveInfo; 30 import android.content.res.Resources; 31 import android.graphics.drawable.Icon; 32 import android.os.Bundle; 33 import android.text.TextUtils; 34 35 import androidx.preference.Preference; 36 37 import com.android.car.apps.common.util.Themes; 38 import com.android.car.settings.R; 39 import com.android.car.ui.preference.CarUiPreference; 40 41 import java.util.HashMap; 42 import java.util.List; 43 import java.util.Map; 44 45 /** 46 * Loads Activity with TileUtils.EXTRA_SETTINGS_ACTION. 47 */ 48 // TODO: investigate using SettingsLib Tiles. 49 public class ExtraSettingsLoader { 50 private static final Logger LOG = new Logger(ExtraSettingsLoader.class); 51 private static final String META_DATA_PREFERENCE_CATEGORY = "com.android.settings.category"; 52 private Map<Preference, Bundle> mPreferenceBundleMap; 53 private final Context mContext; 54 ExtraSettingsLoader(Context context)55 public ExtraSettingsLoader(Context context) { 56 mContext = context; 57 mPreferenceBundleMap = new HashMap<>(); 58 } 59 60 /** 61 * Returns a map of {@link Preference} and {@link Bundle} representing settings injected from 62 * system apps and their metadata. The given intent must specify the action to use for 63 * resolving activities and a category with the key "com.android.settings.category" and one of 64 * the values in {@link com.android.settingslib.drawer.CategoryKey}. 65 * 66 * @param intent intent specifying the extra settings category to load 67 */ loadPreferences(Intent intent)68 public Map<Preference, Bundle> loadPreferences(Intent intent) { 69 PackageManager pm = mContext.getPackageManager(); 70 List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent, 71 PackageManager.GET_META_DATA, ActivityManager.getCurrentUser()); 72 73 String extraCategory = intent.getStringExtra(META_DATA_PREFERENCE_CATEGORY); 74 for (ResolveInfo resolved : results) { 75 if (!resolved.system) { 76 // Do not allow any app to be added to settings, only system ones. 77 continue; 78 } 79 String title = null; 80 String summary = null; 81 String category = null; 82 ActivityInfo activityInfo = resolved.activityInfo; 83 Bundle metaData = activityInfo.metaData; 84 try { 85 Resources res = pm.getResourcesForApplication(activityInfo.packageName); 86 if (metaData.containsKey(META_DATA_PREFERENCE_TITLE)) { 87 if (metaData.get(META_DATA_PREFERENCE_TITLE) instanceof Integer) { 88 title = res.getString(metaData.getInt(META_DATA_PREFERENCE_TITLE)); 89 } else { 90 title = metaData.getString(META_DATA_PREFERENCE_TITLE); 91 } 92 } 93 if (TextUtils.isEmpty(title)) { 94 LOG.d("no title."); 95 title = activityInfo.loadLabel(pm).toString(); 96 } 97 if (metaData.containsKey(META_DATA_PREFERENCE_SUMMARY)) { 98 if (metaData.get(META_DATA_PREFERENCE_SUMMARY) instanceof Integer) { 99 summary = res.getString(metaData.getInt(META_DATA_PREFERENCE_SUMMARY)); 100 } else { 101 summary = metaData.getString(META_DATA_PREFERENCE_SUMMARY); 102 } 103 } else { 104 LOG.d("no description."); 105 } 106 if (metaData.containsKey(META_DATA_PREFERENCE_CATEGORY)) { 107 if (metaData.get(META_DATA_PREFERENCE_CATEGORY) instanceof Integer) { 108 category = res.getString(metaData.getInt(META_DATA_PREFERENCE_CATEGORY)); 109 } else { 110 category = metaData.getString(META_DATA_PREFERENCE_CATEGORY); 111 } 112 } else { 113 LOG.d("no category."); 114 } 115 } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) { 116 LOG.d("Couldn't find info", e); 117 } 118 Icon icon = null; 119 if (metaData.containsKey(META_DATA_PREFERENCE_ICON)) { 120 int iconRes = metaData.getInt(META_DATA_PREFERENCE_ICON); 121 icon = Icon.createWithResource(activityInfo.packageName, iconRes); 122 } else { 123 icon = Icon.createWithResource(mContext, R.drawable.ic_settings_gear); 124 LOG.d("use default icon."); 125 } 126 Intent extraSettingIntent = 127 new Intent().setClassName(activityInfo.packageName, activityInfo.name); 128 if (category == null) { 129 // If category is not specified or not supported, default to device. 130 category = CATEGORY_DEVICE; 131 } 132 133 if (!TextUtils.equals(extraCategory, category)) { 134 continue; 135 } 136 CarUiPreference preference = new CarUiPreference(mContext); 137 preference.setTitle(title); 138 preference.setSummary(summary); 139 if (icon != null) { 140 preference.setIcon(icon.loadDrawable(mContext)); 141 preference.getIcon().setTintList( 142 Themes.getAttrColorStateList(mContext, R.attr.iconColor)); 143 } 144 preference.setIntent(extraSettingIntent); 145 mPreferenceBundleMap.put(preference, metaData); 146 } 147 return mPreferenceBundleMap; 148 } 149 } 150