Merge "Add dialog for changing display name for mobile network"

This commit is contained in:
TreeHugger Robot
2019-02-01 04:58:45 +00:00
committed by Android (Google) Code Review
7 changed files with 381 additions and 10 deletions

View File

@@ -0,0 +1,64 @@
<?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.
-->
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/sim_content_padding">
<EditText
android:id="@+id/edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:maxLength="50"
android:singleLine="true">
<requestFocus/>
</EditText>
<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
style="@style/device_info_dialog_label"
android:id="@+id/number_label"
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_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/device_info_not_available"/>
</LinearLayout>
</ScrollView>

View File

@@ -31,4 +31,7 @@
<item type="id" name="action_drag_move_top" />
<item type="id" name="action_drag_move_bottom" />
<item type="id" name="action_drag_remove" />
<!-- For a menu item allowing users to edit a SIM display name -->
<item type="id" name="edit_sim_name" />
</resources>

View File

@@ -10456,6 +10456,14 @@
<!-- Summary for an item in the page listing multiple mobile service subscriptions, indicating
that service is inactive and is tied to an eSIM profile [CHAR LIMIT=40] -->
<string name="mobile_network_inactive_esim">Inactive eSIM</string>
<!-- Title of a dialog that lets a user modify the display name used for a mobile network
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>
<!-- Title for preferred network type [CHAR LIMIT=NONE] -->
<string name="preferred_network_mode_title">Preferred network type</string>

View File

@@ -97,13 +97,6 @@ public class MobileNetworkActivity extends SettingsBaseActivity {
actionBar.setDisplayHomeAsUpEnabled(true);
}
// Set the title to the name of the subscription. If we don't have subscription info, the
// title will just default to the label for this activity that's already specified in
// AndroidManifest.xml.
final SubscriptionInfo subscription = getSubscription();
if (subscription != null) {
setTitle(subscription.getDisplayName());
}
updateSubscriptions(savedInstanceState);
}
@@ -136,6 +129,14 @@ public class MobileNetworkActivity extends SettingsBaseActivity {
@VisibleForTesting
void updateSubscriptions(Bundle savedInstanceState) {
// Set the title to the name of the subscription. If we don't have subscription info, the
// title will just default to the label for this activity that's already specified in
// AndroidManifest.xml.
final SubscriptionInfo subscription = getSubscription();
if (subscription != null) {
setTitle(subscription.getDisplayName());
}
mSubscriptionInfos = mSubscriptionManager.getActiveSubscriptionInfoList(true);
if (!FeatureFlagPersistent.isEnabled(this, FeatureFlags.NETWORK_INTERNET_V2)) {

View File

@@ -28,9 +28,9 @@ import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import com.android.internal.telephony.TelephonyIntents;
import com.android.settings.R;
@@ -52,6 +52,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class MobileNetworkSettings extends RestrictedDashboardFragment {
@@ -219,6 +222,31 @@ public class MobileNetworkSettings extends RestrictedDashboardFragment {
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (FeatureFlagPersistent.isEnabled(getContext(), FeatureFlags.NETWORK_INTERNET_V2) &&
mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
final MenuItem item = menu.add(Menu.NONE, R.id.edit_sim_name, Menu.NONE,
R.string.mobile_network_sim_name);
item.setIcon(com.android.internal.R.drawable.ic_mode_edit);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
}
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
if (FeatureFlagPersistent.isEnabled(getContext(), FeatureFlags.NETWORK_INTERNET_V2) &&
mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
if (menuItem.getItemId() == R.id.edit_sim_name) {
RenameMobileNetworkDialogFragment.newInstance(mSubId).show(
getFragmentManager(), RenameMobileNetworkDialogFragment.TAG);
return true;
}
}
return super.onOptionsItemSelected(menuItem);
}
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override

View File

@@ -0,0 +1,137 @@
/*
* 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.settings.network.telephony;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Bundle;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.BidiFormatter;
import android.text.TextDirectionHeuristics;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settingslib.DeviceInfoUtils;
import androidx.annotation.NonNull;
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 */
public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragment {
public static final String TAG ="RenameMobileNetwork";
private static final String KEY_SUBSCRIPTION_ID = "subscription_id";
private TelephonyManager mTelephonyManager;
private SubscriptionManager mSubscriptionManager;
private int mSubId;
private EditText mNameView;
public static RenameMobileNetworkDialogFragment newInstance(int subscriptionId) {
final Bundle args = new Bundle(1);
args.putInt(KEY_SUBSCRIPTION_ID, subscriptionId);
final RenameMobileNetworkDialogFragment fragment = new RenameMobileNetworkDialogFragment();
fragment.setArguments(args);
return fragment;
}
@VisibleForTesting
protected TelephonyManager getTelephonyManager(Context context) {
return context.getSystemService(TelephonyManager.class);
}
@VisibleForTesting
protected SubscriptionManager getSubscriptionManager(Context context) {
return context.getSystemService(SubscriptionManager.class);
}
@VisibleForTesting
protected EditText getNameView() {
return mNameView;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mTelephonyManager = getTelephonyManager(context);
mSubscriptionManager = getSubscriptionManager(context);
mSubId = getArguments().getInt(KEY_SUBSCRIPTION_ID);
}
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
final LayoutInflater layoutInflater = builder.getContext().getSystemService(
LayoutInflater.class);
final View view = layoutInflater.inflate(R.layout.dialog_mobile_network_rename, null);
populateView(view);
builder.setTitle(R.string.mobile_network_sim_name)
.setView(view)
.setPositiveButton(R.string.mobile_network_sim_name_rename, (dialog, which) -> {
SubscriptionInfo currentInfo = mSubscriptionManager.getActiveSubscriptionInfo(
mSubId);
String newName = mNameView.getText().toString();
if (currentInfo != null && !currentInfo.getDisplayName().equals(newName)) {
mSubscriptionManager.setDisplayName(newName, mSubId);
}
})
.setNegativeButton(android.R.string.cancel, null);
return builder.create();
}
@VisibleForTesting
protected void populateView(View view) {
mNameView = (EditText) view.findViewById(R.id.edittext);
final SubscriptionInfo info = mSubscriptionManager.getActiveSubscriptionInfo(mSubId);
if (info == null) {
Log.w(TAG, "got null SubscriptionInfo for mSubId:" + mSubId);
return;
}
final CharSequence displayName = info.getDisplayName();
mNameView.setText(displayName);
if (!TextUtils.isEmpty(displayName)) {
mNameView.setSelection(displayName.length());
}
final TextView operatorName = view.findViewById(R.id.operator_name_value);
final ServiceState serviceState = mTelephonyManager.getServiceStateForSubscriber(mSubId);
operatorName.setText(serviceState.getOperatorAlphaLong());
final TextView phoneNumber = view.findViewById(R.id.number_value);
final String formattedNumber = DeviceInfoUtils.getFormattedPhoneNumber(getContext(), info);
phoneNumber.setText(BidiFormatter.getInstance().unicodeWrap(formattedNumber,
TextDirectionHeuristics.LTR));
}
@Override
public int getMetricsCategory() {
return SettingsEnums.MOBILE_NETWORK_RENAME_DIALOG;
}
}

View File

@@ -0,0 +1,130 @@
/*
* 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.settings.network.telephony;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.DialogInterface;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.widget.Button;
import android.widget.EditText;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowAlertDialogCompat.class)
public class RenameMobileNetworkDialogFragmentTest {
@Mock
private TelephonyManager mTelephonyMgr;
@Mock
private SubscriptionManager mSubscriptionMgr;
@Mock
private SubscriptionInfo mSubscriptionInfo;
private FragmentActivity mActivity;
private RenameMobileNetworkDialogFragment mFragment;
private int mSubscriptionId = 1234;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mActivity = spy(Robolectric.buildActivity(FragmentActivity.class).setup().get());
when(mSubscriptionInfo.getSubscriptionId()).thenReturn(mSubscriptionId);
when(mSubscriptionInfo.getDisplayName()).thenReturn("test");
mFragment = spy(RenameMobileNetworkDialogFragment.newInstance(mSubscriptionId));
doReturn(mTelephonyMgr).when(mFragment).getTelephonyManager(any());
doReturn(mSubscriptionMgr).when(mFragment).getSubscriptionManager(any());
final ServiceState serviceState = mock(ServiceState.class);
when(serviceState.getOperatorAlphaLong()).thenReturn("fake carrier name");
when(mTelephonyMgr.getServiceStateForSubscriber(mSubscriptionId)).thenReturn(serviceState);
}
@Test
public void dialog_subscriptionMissing_noCrash() {
final AlertDialog dialog = startDialog();
final Button negativeButton = dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
assertThat(negativeButton).isNotNull();
negativeButton.performClick();
}
@Test
public void dialog_cancelButtonClicked_setDisplayNameNotCalled() {
when(mSubscriptionMgr.getActiveSubscriptionInfo(mSubscriptionId)).thenReturn(
mSubscriptionInfo);
final AlertDialog dialog = startDialog();
final EditText nameView = mFragment.getNameView();
nameView.setText("test2");
final Button negativeButton = dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
negativeButton.performClick();
verify(mSubscriptionMgr, never()).setDisplayName(anyString(), anyInt());
}
@Test
public void dialog_renameButtonClicked_setDisplayNameCalled() {
when(mSubscriptionMgr.getActiveSubscriptionInfo(mSubscriptionId)).thenReturn(
mSubscriptionInfo);
final AlertDialog dialog = startDialog();
final EditText nameView = mFragment.getNameView();
nameView.setText("test2");
final Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
positiveButton.performClick();
final ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(mSubscriptionMgr).setDisplayName(captor.capture(), eq(mSubscriptionId));
assertThat(captor.getValue()).isEqualTo("test2");
}
/** Helper method to start the dialog */
private AlertDialog startDialog() {
mFragment.show(mActivity.getSupportFragmentManager(), null);
return ShadowAlertDialogCompat.getLatestAlertDialog();
}
}