1 /* 2 * Copyright (C) 2019 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.settings.network.telephony; 18 19 import android.app.Dialog; 20 import android.app.settings.SettingsEnums; 21 import android.content.Context; 22 import android.content.res.Configuration; 23 import android.content.res.Resources; 24 import android.graphics.Paint; 25 import android.graphics.drawable.ShapeDrawable; 26 import android.graphics.drawable.shapes.OvalShape; 27 import android.os.Bundle; 28 import android.telephony.SubscriptionInfo; 29 import android.telephony.SubscriptionManager; 30 import android.telephony.TelephonyManager; 31 import android.text.TextUtils; 32 import android.util.Log; 33 import android.view.LayoutInflater; 34 import android.view.View; 35 import android.view.ViewGroup; 36 import android.widget.ArrayAdapter; 37 import android.widget.EditText; 38 import android.widget.ImageView; 39 import android.widget.Spinner; 40 import android.widget.TextView; 41 42 import androidx.annotation.NonNull; 43 import androidx.annotation.Nullable; 44 import androidx.annotation.VisibleForTesting; 45 import androidx.appcompat.app.AlertDialog; 46 47 import com.android.settings.R; 48 import com.android.settings.core.instrumentation.InstrumentedDialogFragment; 49 import com.android.settings.network.SubscriptionUtil; 50 import com.android.settingslib.DeviceInfoUtils; 51 52 import com.google.common.collect.ImmutableMap; 53 54 import java.util.List; 55 import java.util.Map; 56 57 /** 58 * A dialog allowing the display name of a mobile network subscription to be changed 59 */ 60 public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragment { 61 62 public static final String TAG = "RenameMobileNetwork"; 63 64 private static final String KEY_SUBSCRIPTION_ID = "subscription_id"; 65 66 private TelephonyManager mTelephonyManager; 67 private SubscriptionManager mSubscriptionManager; 68 private int mSubId; 69 private EditText mNameView; 70 private Spinner mColorSpinner; 71 private Color[] mColors; 72 private Map<Integer, Integer> mLightDarkMap; 73 newInstance(int subscriptionId)74 public static RenameMobileNetworkDialogFragment newInstance(int subscriptionId) { 75 final Bundle args = new Bundle(1); 76 args.putInt(KEY_SUBSCRIPTION_ID, subscriptionId); 77 final RenameMobileNetworkDialogFragment fragment = new RenameMobileNetworkDialogFragment(); 78 fragment.setArguments(args); 79 return fragment; 80 } 81 82 @VisibleForTesting getTelephonyManager(Context context)83 protected TelephonyManager getTelephonyManager(Context context) { 84 return context.getSystemService(TelephonyManager.class); 85 } 86 87 @VisibleForTesting getSubscriptionManager(Context context)88 protected SubscriptionManager getSubscriptionManager(Context context) { 89 return context.getSystemService(SubscriptionManager.class); 90 } 91 92 @VisibleForTesting getNameView()93 protected EditText getNameView() { 94 return mNameView; 95 } 96 97 @VisibleForTesting getColorSpinnerView()98 protected Spinner getColorSpinnerView() { 99 return mColorSpinner; 100 } 101 102 @Override onAttach(Context context)103 public void onAttach(Context context) { 104 super.onAttach(context); 105 mTelephonyManager = getTelephonyManager(context); 106 mSubscriptionManager = getSubscriptionManager(context); 107 mSubId = getArguments().getInt(KEY_SUBSCRIPTION_ID); 108 Resources res = context.getResources(); 109 mLightDarkMap = ImmutableMap.<Integer, Integer>builder() 110 .put(res.getInteger(R.color.SIM_color_cyan), 111 res.getInteger(R.color.SIM_dark_mode_color_cyan)) 112 .put(res.getInteger(R.color.SIM_color_blue800), 113 res.getInteger(R.color.SIM_dark_mode_color_blue)) 114 .put(res.getInteger(R.color.SIM_color_green800), 115 res.getInteger(R.color.SIM_dark_mode_color_green)) 116 .put(res.getInteger(R.color.SIM_color_purple800), 117 res.getInteger(R.color.SIM_dark_mode_color_purple)) 118 .put(res.getInteger(R.color.SIM_color_pink800), 119 res.getInteger(R.color.SIM_dark_mode_color_pink)) 120 .put(res.getInteger(R.color.SIM_color_orange), 121 res.getInteger(R.color.SIM_dark_mode_color_orange)) 122 .build(); 123 } 124 125 @NonNull 126 @Override onCreateDialog(@ullable Bundle savedInstanceState)127 public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { 128 mColors = getColors(); 129 130 final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 131 final LayoutInflater layoutInflater = builder.getContext().getSystemService( 132 LayoutInflater.class); 133 final View view = layoutInflater.inflate(R.layout.dialog_mobile_network_rename, null); 134 populateView(view); 135 builder.setTitle(R.string.mobile_network_sim_name) 136 .setView(view) 137 .setPositiveButton(R.string.mobile_network_sim_name_rename, (dialog, which) -> { 138 mSubscriptionManager.setDisplayName(mNameView.getText().toString(), mSubId, 139 SubscriptionManager.NAME_SOURCE_USER_INPUT); 140 final Color color = (mColorSpinner == null) ? mColors[0] 141 : mColors[mColorSpinner.getSelectedItemPosition()]; 142 mSubscriptionManager.setIconTint(color.getColor(), mSubId); 143 }) 144 .setNegativeButton(android.R.string.cancel, null); 145 return builder.create(); 146 } 147 148 @VisibleForTesting populateView(View view)149 protected void populateView(View view) { 150 mNameView = view.findViewById(R.id.name_edittext); 151 SubscriptionInfo info = null; 152 final List<SubscriptionInfo> infoList = mSubscriptionManager 153 .getAvailableSubscriptionInfoList(); 154 if (infoList != null) { 155 for (SubscriptionInfo subInfo : infoList) { 156 if (subInfo.getSubscriptionId() == mSubId) { 157 info = subInfo; 158 break; 159 } 160 } 161 } 162 if (info == null) { 163 Log.w(TAG, "got null SubscriptionInfo for mSubId:" + mSubId); 164 return; 165 } 166 final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName( 167 info, getContext()); 168 mNameView.setText(displayName); 169 if (!TextUtils.isEmpty(displayName)) { 170 mNameView.setSelection(displayName.length()); 171 } 172 173 mColorSpinner = view.findViewById(R.id.color_spinner); 174 final ColorAdapter adapter = new ColorAdapter(getContext(), 175 R.layout.dialog_mobile_network_color_picker_item, mColors); 176 mColorSpinner.setAdapter(adapter); 177 mColorSpinner.setSelection(getSimColorIndex(info.getIconTint())); 178 179 final TextView operatorName = view.findViewById(R.id.operator_name_value); 180 mTelephonyManager = mTelephonyManager.createForSubscriptionId(mSubId); 181 operatorName.setText(info.getCarrierName()); 182 183 final TextView phoneTitle = view.findViewById(R.id.number_label); 184 phoneTitle.setVisibility(info.isOpportunistic() ? View.GONE : View.VISIBLE); 185 186 final TextView phoneNumber = view.findViewById(R.id.number_value); 187 final String pn = DeviceInfoUtils.getBidiFormattedPhoneNumber(getContext(), info); 188 if (!TextUtils.isEmpty(pn)) { 189 phoneNumber.setText(pn); 190 } 191 } 192 193 @Override getMetricsCategory()194 public int getMetricsCategory() { 195 return SettingsEnums.MOBILE_NETWORK_RENAME_DIALOG; 196 } 197 198 private class ColorAdapter extends ArrayAdapter<Color> { 199 200 private Context mContext; 201 private int mItemResId; 202 ColorAdapter(Context context, int resource, Color[] colors)203 public ColorAdapter(Context context, int resource, Color[] colors) { 204 super(context, resource, colors); 205 mContext = context; 206 mItemResId = resource; 207 } 208 209 @Override getView(int position, View convertView, ViewGroup parent)210 public View getView(int position, View convertView, ViewGroup parent) { 211 final LayoutInflater inflater = (LayoutInflater) 212 mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 213 214 if (convertView == null) { 215 convertView = inflater.inflate(mItemResId, null); 216 } 217 boolean isDarkMode = false; 218 if ((getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) 219 == Configuration.UI_MODE_NIGHT_YES) { 220 isDarkMode = true; 221 } 222 ((ImageView) convertView.findViewById(R.id.color_icon)) 223 .setImageDrawable(getItem(position).getDrawable(isDarkMode)); 224 ((TextView) convertView.findViewById(R.id.color_label)) 225 .setText(getItem(position).getLabel()); 226 227 return convertView; 228 } 229 230 @Override getDropDownView(int position, View convertView, ViewGroup parent)231 public View getDropDownView(int position, View convertView, ViewGroup parent) { 232 return getView(position, convertView, parent); 233 } 234 } 235 getColors()236 private Color[] getColors() { 237 final Resources res = getContext().getResources(); 238 final int[] colorInts = res.getIntArray(R.array.sim_color_light); 239 final String[] colorStrings = res.getStringArray(R.array.color_picker); 240 final int iconSize = res.getDimensionPixelSize(R.dimen.color_swatch_size); 241 final int strokeWidth = res.getDimensionPixelSize(R.dimen.color_swatch_stroke_width); 242 final Color[] colors = new Color[colorInts.length]; 243 for (int i = 0; i < colors.length; i++) { 244 colors[i] = new Color(colorStrings[i], colorInts[i], iconSize, strokeWidth); 245 } 246 return colors; 247 } 248 249 private class Color { 250 251 private String mLabel; 252 private int mColor; 253 private ShapeDrawable mDrawable; 254 Color(String label, int color, int iconSize, int strokeWidth)255 private Color(String label, int color, int iconSize, int strokeWidth) { 256 mLabel = label; 257 mColor = color; 258 mDrawable = new ShapeDrawable(new OvalShape()); 259 mDrawable.setIntrinsicHeight(iconSize); 260 mDrawable.setIntrinsicWidth(iconSize); 261 mDrawable.getPaint().setStrokeWidth(strokeWidth); 262 mDrawable.getPaint().setStyle(Paint.Style.FILL_AND_STROKE); 263 mDrawable.getPaint().setColor(color); 264 } 265 getLabel()266 private String getLabel() { 267 return mLabel; 268 } 269 getColor()270 private int getColor() { 271 return mColor; 272 } 273 getDrawable(boolean isDarkMode)274 private ShapeDrawable getDrawable(boolean isDarkMode) { 275 if (isDarkMode) { 276 mDrawable.getPaint().setColor(getDarkColor(mColor)); 277 } 278 return mDrawable; 279 } 280 } 281 getDarkColor(int lightColor)282 private int getDarkColor(int lightColor) { 283 return mLightDarkMap.getOrDefault(lightColor, lightColor); 284 } 285 286 /* 287 * Get the color index from previous color that defined in Android OS 288 * (frameworks/base/core/res/res/values/arrays.xml). If can't find the color, continue to look 289 * for it in the new color plattee. If not, give it the first index. 290 */ 291 getSimColorIndex(int color)292 private int getSimColorIndex(int color) { 293 int index = -1; 294 final int[] previousSimColorInts = 295 getContext().getResources().getIntArray(com.android.internal.R.array.sim_colors); 296 for (int i = 0; i < previousSimColorInts.length; i++) { 297 if (previousSimColorInts[i] == color) { 298 index = i; 299 } 300 } 301 302 if (index == -1) { 303 for (int i = 0; i < mColors.length; i++) { 304 if (mColors[i].getColor() == color) { 305 index = i; 306 } 307 } 308 } 309 310 return index == -1 ? 0 : index; 311 } 312 } 313