1 /* 2 * Copyright (C) 2020 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.car.settings.common.ExtraSettingsLoader.META_DATA_PREFERENCE_IS_TOP_LEVEL; 20 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON; 21 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_TINTABLE; 22 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_URI; 23 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT; 24 25 import android.content.ContentResolver; 26 import android.content.Context; 27 import android.content.pm.PackageManager; 28 import android.content.res.Resources; 29 import android.graphics.drawable.Drawable; 30 import android.net.Uri; 31 import android.os.Bundle; 32 import android.text.TextUtils; 33 34 import androidx.annotation.DrawableRes; 35 import androidx.annotation.Nullable; 36 37 import com.android.car.settings.R; 38 39 import java.util.List; 40 41 /** Contains utility functions for injected settings. */ 42 public class ExtraSettingsUtil { 43 private static final Logger LOG = new Logger(ExtraSettingsUtil.class); 44 45 /** 46 * See {@link #createIcon(Context, Bundle, String, int) 47 * <p> 48 * Will return null if the provided metadata does not specify 49 * {@link com.android.settingslib.drawer.TileUtils#META_DATA_PREFERENCE_ICON} but contains 50 * {@link com.android.settingslib.drawer.TileUtils#META_DATA_PREFERENCE_ICON_URI}. 51 */ 52 @Nullable createIcon(Context context, Bundle metaData, String packageName)53 public static Drawable createIcon(Context context, Bundle metaData, String packageName) { 54 if (metaData.containsKey(META_DATA_PREFERENCE_ICON)) { 55 int iconRes = metaData.getInt(META_DATA_PREFERENCE_ICON); 56 return createIcon(context, metaData, packageName, iconRes); 57 } else if (metaData.containsKey(META_DATA_PREFERENCE_ICON_URI)) { 58 return null; 59 } 60 return createIcon(context, metaData, packageName, /* resId= */ 0); 61 } 62 63 /** 64 * Returns an icon for an injected preference with the necessary styling, or null if the 65 * provided {@code resId} could not be loaded. 66 */ 67 @Nullable createIcon(Context context, Bundle metaData, String packageName, @DrawableRes int resId)68 public static Drawable createIcon(Context context, Bundle metaData, String packageName, 69 @DrawableRes int resId) { 70 Drawable icon = null; 71 if (resId != 0) { 72 icon = loadDrawableFromPackage(context, packageName, resId); 73 } 74 if (icon == null) { 75 return null; 76 } 77 if (metaData.getBoolean(META_DATA_PREFERENCE_IS_TOP_LEVEL, /* defaultValue= */ false)) { 78 icon.mutate().setTintList( 79 context.getColorStateList(R.color.top_level_injected_icon_default)); 80 icon = new TopLevelIcon(context, icon, R.dimen.top_level_foreground_icon_inset); 81 ((TopLevelIcon) icon).setBackgroundColor(context, metaData, packageName); 82 } else if (isIconTintable(metaData)) { 83 // If the icon is tintable, tint it with the default icon color 84 icon.mutate().setTintList(context.getColorStateList(R.color.icon_color_default)); 85 } 86 return icon; 87 } 88 89 /** 90 * Returns whether or not an icon is tintable given the injected setting metadata. 91 */ isIconTintable(Bundle metaData)92 public static boolean isIconTintable(Bundle metaData) { 93 if (metaData.containsKey(META_DATA_PREFERENCE_ICON_TINTABLE)) { 94 return metaData.getBoolean(META_DATA_PREFERENCE_ICON_TINTABLE); 95 } 96 return false; 97 } 98 99 /** 100 * Returns a drawable from an resource's package context. 101 */ loadDrawableFromPackage(Context context, String resPackage, int resId)102 public static Drawable loadDrawableFromPackage(Context context, String resPackage, int resId) { 103 try { 104 return context.createPackageContext(resPackage, /* flags= */ 0) 105 .getDrawable(resId); 106 } catch (PackageManager.NameNotFoundException ex) { 107 LOG.e("loadDrawableFromPackage: package name not found: ", ex); 108 } catch (Resources.NotFoundException ex) { 109 LOG.w("loadDrawableFromPackage: resource not found with id " + resId, ex); 110 } 111 return null; 112 } 113 114 /** 115 * Returns the complete uri from the meta data key of the injected setting metadata. 116 * 117 * A complete uri should contain at least one path segment and be one of the following types: 118 * content://authority/method 119 * content://authority/method/key 120 * 121 * If the uri from the tile is not complete, build a uri by the default method and the 122 * preference key. 123 */ getCompleteUri(Bundle metaData, String metaDataKey, String defaultMethod)124 public static Uri getCompleteUri(Bundle metaData, String metaDataKey, String defaultMethod) { 125 String uriString = metaData.getString(metaDataKey); 126 if (TextUtils.isEmpty(uriString)) { 127 return null; 128 } 129 130 Uri uri = Uri.parse(uriString); 131 List<String> pathSegments = uri.getPathSegments(); 132 if (pathSegments != null && !pathSegments.isEmpty()) { 133 return uri; 134 } 135 136 String key = metaData.getString(META_DATA_PREFERENCE_KEYHINT); 137 if (TextUtils.isEmpty(key)) { 138 LOG.w("Please specify the meta-data " + META_DATA_PREFERENCE_KEYHINT 139 + " in AndroidManifest.xml for " + uriString); 140 return buildUri(uri.getAuthority(), defaultMethod); 141 } 142 return buildUri(uri.getAuthority(), defaultMethod, key); 143 } 144 buildUri(String authority, String method, String key)145 private static Uri buildUri(String authority, String method, String key) { 146 return new Uri.Builder() 147 .scheme(ContentResolver.SCHEME_CONTENT) 148 .authority(authority) 149 .appendPath(method) 150 .appendPath(key) 151 .build(); 152 } 153 buildUri(String authority, String method)154 private static Uri buildUri(String authority, String method) { 155 return new Uri.Builder() 156 .scheme(ContentResolver.SCHEME_CONTENT) 157 .authority(authority) 158 .appendPath(method) 159 .build(); 160 } 161 } 162