Add SIM color picker

Bug: 133193155
Test: make ROBOTEST_FILTER="(RenameMobileNetwork*)" RunSettingsRoboTests -j48

Change-Id: Ifae8b77bc5b4ba1039ede70889468a018f57d78f
This commit is contained in:
Christine Franks
2019-05-24 10:52:55 -07:00
parent d133a026cd
commit 8869db9555
6 changed files with 253 additions and 41 deletions

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="?android:attr/selectableItemBackground" >
<ImageView
android:id="@+id/color_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/sim_label_padding"
android:layout_gravity="center_vertical" />
<TextView
android:id="@+id/color_label"
android:gravity="center_vertical"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:paddingTop="@dimen/sim_label_padding"
android:paddingBottom="@dimen/sim_label_padding"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
android:textColor="?android:attr/textColorPrimary"/>
</LinearLayout>

View File

@@ -21,44 +21,89 @@
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/sim_content_padding">
android:layout_height="wrap_content">
<EditText
android:id="@+id/edittext"
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:maxLength="50"
android:singleLine="true">
<requestFocus/>
</EditText>
android:paddingEnd="@dimen/sim_content_padding"
android:paddingStart="@dimen/sim_content_padding">
<TextView
style="@style/device_info_dialog_label"
android:id="@+id/operator_name_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/status_operator"/>
<TextView
style="@style/device_info_dialog_value"
android:id="@+id/operator_name_value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/device_info_not_available"/>
<TextView
android:id="@+id/name_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/sim_label_padding"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
android:textColor="?android:attr/textColorPrimary"
android:text="@string/mobile_network_sim_name_label"/>
<TextView
style="@style/device_info_dialog_label"
android:id="@+id/number_label"
<EditText
android:id="@+id/name_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:paddingTop="@dimen/sim_label_padding"
android:maxLength="50"
android:singleLine="true"/>
<TextView
android:id="@+id/color_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/sim_label_padding"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
android:textColor="?android:attr/textColorPrimary"
android:text="@string/mobile_network_sim_color_label"/>
</LinearLayout>
<Spinner
android:id="@+id/color_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/status_number_sim_status"/>
<TextView
style="@style/device_info_dialog_value"
android:id="@+id/number_value"
android:layout_marginStart="@dimen/sim_color_spinner_padding"
android:layout_marginEnd="@dimen/sim_color_spinner_padding"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/device_info_not_available"/>
android:paddingEnd="@dimen/sim_content_padding"
android:paddingStart="@dimen/sim_content_padding">
<TextView
android:id="@+id/operator_name_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/sim_label_padding"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
android:textColor="?android:attr/textColorPrimary"
android:text="@string/status_operator"/>
<TextView
android:id="@+id/operator_name_value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/device_info_not_available"/>
<TextView
android:id="@+id/number_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/sim_label_padding"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
android:textColor="?android:attr/textColorPrimary"
android:text="@string/status_number_sim_status"/>
<TextView
android:id="@+id/number_value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/device_info_not_available"/>
</LinearLayout>
</LinearLayout>
</ScrollView>

View File

@@ -166,6 +166,7 @@
<dimen name="sim_dialog_margin_bottom">16dip</dimen>
<!-- SIM Dialog padding -->
<dimen name="sim_dialog_padding">8dip</dimen>
<dimen name="sim_color_spinner_padding">12dip</dimen>
<dimen name="sim_label_padding">16dip</dimen>
<dimen name="sim_content_padding">24dip</dimen>
<!-- Sim Card Name length -->

View File

@@ -10956,10 +10956,14 @@
subscription in various places in the Settings app. The default name is typically just the
carrier name, but especially in multi-SIM configurations users may want to use a different
name. [CHAR LIMIT=40] -->
<string name="mobile_network_sim_name">SIM name</string>
<!-- Label on the confirmation button of a dialog that lets a user set the display name of a
mobile network subscription [CHAR LIMIT=20] -->
<string name="mobile_network_sim_name_rename">Rename</string>
<string name="mobile_network_sim_name">SIM name &amp; color</string>
<!-- Label for an item listing the name of the SIM that the user has specified. [CHAR LIMIT=40] -->
<string name="mobile_network_sim_name_label">Name</string>
<!-- Label for an item listing the color of the SIM that the user has specified. [CHAR LIMIT=40] -->
<string name="mobile_network_sim_color_label">Color (used by compatible apps)</string>
<!-- Label on the confirmation button of a dialog that lets a user set the display name and
color of a mobile network subscription [CHAR LIMIT=20] -->
<string name="mobile_network_sim_name_rename">Save</string>
<!-- Label for the on position of a switch on the mobile network details page which allows
disabling/enabling a SIM. The SIM is enabled in this state. [CHAR LIMIT=40] -->
<string name="mobile_network_use_sim_on">Use SIM</string>

View File

@@ -19,6 +19,10 @@ package com.android.settings.network.telephony;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Paint;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.os.Bundle;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
@@ -30,7 +34,12 @@ import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import com.android.settings.R;
@@ -42,9 +51,12 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
/** A dialog allowing the display name of a mobile network subscription to be changed */
/**
* A dialog allowing the display name of a mobile network subscription to be changed
*/
public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragment {
public static final String TAG ="RenameMobileNetwork";
public static final String TAG = "RenameMobileNetwork";
private static final String KEY_SUBSCRIPTION_ID = "subscription_id";
@@ -52,6 +64,8 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
private SubscriptionManager mSubscriptionManager;
private int mSubId;
private EditText mNameView;
private Spinner mColorSpinner;
private Color[] mColors;
public static RenameMobileNetworkDialogFragment newInstance(int subscriptionId) {
final Bundle args = new Bundle(1);
@@ -76,6 +90,11 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
return mNameView;
}
@VisibleForTesting
protected Spinner getColorSpinnerView() {
return mColorSpinner;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
@@ -87,6 +106,8 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
mColors = getColors();
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
final LayoutInflater layoutInflater = builder.getContext().getSystemService(
LayoutInflater.class);
@@ -95,9 +116,11 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
builder.setTitle(R.string.mobile_network_sim_name)
.setView(view)
.setPositiveButton(R.string.mobile_network_sim_name_rename, (dialog, which) -> {
String newName = mNameView.getText().toString();
mSubscriptionManager.setDisplayName(newName, mSubId,
mSubscriptionManager.setDisplayName(mNameView.getText().toString(), mSubId,
SubscriptionManager.NAME_SOURCE_USER_INPUT);
mSubscriptionManager.setIconTint(
mColors[mColorSpinner.getSelectedItemPosition()].getColor(),
mSubId);
})
.setNegativeButton(android.R.string.cancel, null);
return builder.create();
@@ -105,7 +128,7 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
@VisibleForTesting
protected void populateView(View view) {
mNameView = view.findViewById(R.id.edittext);
mNameView = view.findViewById(R.id.name_edittext);
final SubscriptionInfo info = mSubscriptionManager.getActiveSubscriptionInfo(mSubId);
if (info == null) {
Log.w(TAG, "got null SubscriptionInfo for mSubId:" + mSubId);
@@ -117,6 +140,17 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
mNameView.setSelection(displayName.length());
}
mColorSpinner = view.findViewById(R.id.color_spinner);
final ColorAdapter adapter = new ColorAdapter(getContext(),
R.layout.dialog_mobile_network_color_picker_item, mColors);
mColorSpinner.setAdapter(adapter);
for (int i = 0; i < mColors.length; i++) {
if (mColors[i].getColor() == info.getIconTint()) {
mColorSpinner.setSelection(i);
break;
}
}
final TextView operatorName = view.findViewById(R.id.operator_name_value);
final ServiceState serviceState = mTelephonyManager.getServiceStateForSubscriber(mSubId);
operatorName.setText(serviceState.getOperatorAlphaLong());
@@ -134,4 +168,80 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
public int getMetricsCategory() {
return SettingsEnums.MOBILE_NETWORK_RENAME_DIALOG;
}
private class ColorAdapter extends ArrayAdapter<Color> {
private Context mContext;
private int mItemResId;
public ColorAdapter(Context context, int resource, Color[] colors) {
super(context, resource, colors);
mContext = context;
mItemResId = resource;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final LayoutInflater inflater = (LayoutInflater)
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = inflater.inflate(mItemResId, null);
}
((ImageView) convertView.findViewById(R.id.color_icon))
.setImageDrawable(getItem(position).getDrawable());
((TextView) convertView.findViewById(R.id.color_label))
.setText(getItem(position).getLabel());
return convertView;
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getView(position, convertView, parent);
}
}
private Color[] getColors() {
final Resources res = getContext().getResources();
final int[] colorInts = res.getIntArray(com.android.internal.R.array.sim_colors);
final String[] colorStrings = res.getStringArray(R.array.color_picker);
final int iconSize = res.getDimensionPixelSize(R.dimen.color_swatch_size);
final int strokeWidth = res.getDimensionPixelSize(R.dimen.color_swatch_stroke_width);
final Color[] colors = new Color[colorInts.length];
for (int i = 0; i < colors.length; i++) {
colors[i] = new Color(colorStrings[i], colorInts[i], iconSize, strokeWidth);
}
return colors;
}
private static class Color {
private String mLabel;
private int mColor;
private ShapeDrawable mDrawable;
private Color(String label, int color, int iconSize, int strokeWidth) {
mLabel = label;
mColor = color;
mDrawable = new ShapeDrawable(new OvalShape());
mDrawable.setIntrinsicHeight(iconSize);
mDrawable.setIntrinsicWidth(iconSize);
mDrawable.getPaint().setStrokeWidth(strokeWidth);
mDrawable.getPaint().setStyle(Paint.Style.FILL_AND_STROKE);
mDrawable.getPaint().setColor(color);
}
private String getLabel() {
return mLabel;
}
private int getColor() {
return mColor;
}
private ShapeDrawable getDrawable() {
return mDrawable;
}
}
}

View File

@@ -30,6 +30,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.DialogInterface;
import android.graphics.Color;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -38,6 +39,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
@@ -58,6 +60,7 @@ import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowAlertDialogCompat.class)
public class RenameMobileNetworkDialogFragmentTest {
@Mock
private TelephonyManager mTelephonyMgr;
@Mock
@@ -95,7 +98,7 @@ public class RenameMobileNetworkDialogFragmentTest {
}
@Test
public void dialog_cancelButtonClicked_setDisplayNameNotCalled() {
public void dialog_cancelButtonClicked_setDisplayNameAndIconTintNotCalled() {
when(mSubscriptionMgr.getActiveSubscriptionInfo(mSubscriptionId)).thenReturn(
mSubscriptionInfo);
final AlertDialog dialog = startDialog();
@@ -106,10 +109,11 @@ public class RenameMobileNetworkDialogFragmentTest {
negativeButton.performClick();
verify(mSubscriptionMgr, never()).setDisplayName(anyString(), anyInt(), anyInt());
verify(mSubscriptionMgr, never()).setIconTint(anyInt(), anyInt());
}
@Test
public void dialog_renameButtonClicked_setDisplayNameCalled() {
public void dialog_saveButtonClicked_setDisplayNameAndIconTint() {
when(mSubscriptionMgr.getActiveSubscriptionInfo(mSubscriptionId)).thenReturn(
mSubscriptionInfo);
@@ -117,6 +121,9 @@ public class RenameMobileNetworkDialogFragmentTest {
final EditText nameView = mFragment.getNameView();
nameView.setText("test2");
final Spinner colorSpinnerView = mFragment.getColorSpinnerView();
colorSpinnerView.setSelection(0);
final Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
positiveButton.performClick();
@@ -124,6 +131,8 @@ public class RenameMobileNetworkDialogFragmentTest {
verify(mSubscriptionMgr).setDisplayName(captor.capture(), eq(mSubscriptionId),
eq(SubscriptionManager.NAME_SOURCE_USER_INPUT));
assertThat(captor.getValue()).isEqualTo("test2");
verify(mSubscriptionMgr)
.setIconTint(eq(Color.parseColor("#ff00796b" /* teal */)), eq(mSubscriptionId));
}
@Test
@@ -140,7 +149,9 @@ public class RenameMobileNetworkDialogFragmentTest {
assertThat(view.findViewById(R.id.number_label).getVisibility()).isEqualTo(View.GONE);
}
/** Helper method to start the dialog */
/**
* Helper method to start the dialog
*/
private AlertDialog startDialog() {
mFragment.show(mActivity.getSupportFragmentManager(), null);
return ShadowAlertDialogCompat.getLatestAlertDialog();