Merge changes from topic "mobile_select_migration"

* changes:
  Fix compile error in NetwotkSelectSettings
  Copy NetworkSelectSettings to settings app
This commit is contained in:
TreeHugger Robot
2018-09-21 01:40:29 +00:00
committed by Android (Google) Code Review
10 changed files with 990 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="8.5dp"
android:height="17dp"
android:viewportWidth="12.0"
android:viewportHeight="24.0"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M3.500000,11.000000L1.800000,11.000000L1.800000,4.400000L0.200000,5.100000L0.200000,3.700000l3.100000,-1.300000l0.200000,0.000000L3.500000,11.000000z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M8.600000,5.500000l1.200000,-3.000000l1.900000,0.000000L9.700000,6.700000l2.200000,4.300000L9.900000,11.000000L8.700000,7.900000L7.400000,11.000000L5.500000,11.000000l2.100000,-4.300000L5.600000,2.500000l1.900000,0.000000L8.600000,5.500000z"/>
</vector>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="9.208dp"
android:height="17dp"
android:viewportWidth="13.0"
android:viewportHeight="24.0"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M2.000000,6.000000l0.800000,0.000000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000s0.200000,-0.500000 0.200000,-0.900000c0.000000,-0.300000 -0.100000,-0.600000 -0.200000,-0.800000S3.200000,3.700000 2.900000,3.700000C2.700000,3.700000 2.500000,3.800000 2.300000,4.000000S2.100000,4.400000 2.100000,4.700000L0.500000,4.700000C0.500000,4.000000 0.700000,3.400000 1.100000,3.000000s1.000000,-0.600000 1.700000,-0.600000c0.800000,0.000000 1.400000,0.200000 1.900000,0.600000s0.700000,1.000000 0.700000,1.800000c0.000000,0.400000 -0.100000,0.700000 -0.300000,1.100000S4.600000,6.500000 4.300000,6.600000C4.700000,6.800000 5.000000,7.100000 5.200000,7.400000s0.300000,0.700000 0.300000,1.200000c0.000000,0.800000 -0.200000,1.400000 -0.700000,1.800000s-1.100000,0.700000 -1.900000,0.700000c-0.700000,0.000000 -1.300000,-0.200000 -1.800000,-0.600000s-0.700000,-1.000000 -0.700000,-1.800000L2.000000,8.700000C2.000000,9.000000 2.100000,9.300000 2.300000,9.500000s0.400000,0.300000 0.600000,0.300000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000S3.900000,9.000000 3.900000,8.600000c0.000000,-0.500000 -0.100000,-0.800000 -0.300000,-1.000000S3.200000,7.300000 2.800000,7.300000L2.000000,7.300000L2.000000,6.000000z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M12.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S6.700000,9.000000 6.700000,7.900000L6.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000l-1.600000,0.000000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000s-0.500000,-0.300000 -0.900000,-0.300000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S8.400000,5.000000 8.400000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L10.799999,7.800000L9.600000,7.800000L9.600000,6.600000l2.900000,0.000000L12.500000,9.900000z"/>
</vector>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="4.958dp"
android:height="17dp"
android:viewportWidth="7.0"
android:viewportHeight="24.0"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M6.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S0.700000,9.000000 0.700000,7.900000L0.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000L4.700000,5.200000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S4.000000,3.700000 3.600000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S2.300000,5.000000 2.300000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L4.700000,7.800000L3.500000,7.800000L3.500000,6.600000l2.900000,0.000000L6.400000,9.900000z"/>
</vector>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="9.208dp"
android:height="17dp"
android:viewportWidth="13.0"
android:viewportHeight="24.0"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M2.000000,9.700000l2.000000,0.000000L4.000000,11.000000L0.300000,11.000000L0.300000,2.500000L2.000000,2.500000L2.000000,9.700000z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M8.300000,3.800000L7.000000,3.800000L7.000000,11.000000L5.300000,11.000000L5.300000,3.800000L4.000000,3.800000L4.000000,2.500000l4.300000,0.000000L8.300000,3.800000z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M12.400000,7.300000l-1.700000,0.000000l0.000000,2.400000l2.100000,0.000000L12.799999,11.000000L9.000000,11.000000L9.000000,2.500000l3.700000,0.000000l0.000000,1.300000l-2.100000,0.000000l0.000000,2.100000l1.700000,0.000000L12.300000,7.300000z"/>
</vector>

View File

@@ -351,4 +351,7 @@
<dimen name="homepage_card_padding_top">6dp</dimen>
<dimen name="homepage_card_padding_bottom">6dp</dimen>
<!-- Signal icon in NetworkSelectSetting -->
<dimen name="signal_strength_icon_size">24dp</dimen>
</resources>

View File

@@ -10074,4 +10074,20 @@
<!-- Title of implications of enabling CBRS Data -->
<string name="cbrs_data_switch_summary">CBRS Data</string>
<!-- Available networks screen, name of button when user wants to select network manually [CHAR LIMIT=60] -->
<string name="choose_network_title">Choose network</string>
<!-- Available networks screen, text when no networks connected [CHAR LIMIT=60] -->
<string name="network_disconnected">Disconnected</string>
<!-- Available networks screen, text when network connected [CHAR LIMIT=60] -->
<string name="network_connected">Connected</string>
<!-- Available networks screen, text when a network is connecting [CHAR LIMIT=60] -->
<string name="network_connecting">Connecting\u2026</string>
<!-- Available networks screen, text when a network cannot be connected [CHAR LIMIT=60] -->
<string name="network_could_not_connect">Couldn\u2019t connect</string>
<!-- Available networks screen, text when no networks are found [CHAR LIMIT=NONE] -->
<string name="empty_networks_list">No networks found.</string>
<!-- Available networks screen, toast when an error is encountered when searching for networks [CHAR LIMIT=NONE] -->
<string name="network_query_error">Couldn\u2019t find networks. Try again.</string>
<!-- Text to show this network is forbidden [CHAR LIMIT=NONE] -->
<string name="forbidden_network">(forbidden)</string>
</resources>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 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.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:key="mobile_choose_network_pref_screen"
android:title="@string/choose_network_title">
<PreferenceCategory
android:key="connected_network_operator_preference"/>
<PreferenceCategory
android:key="network_operators_preference"/>
</PreferenceScreen>

View File

@@ -0,0 +1,135 @@
/*
* Copyright (C) 2018 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.mobilenetwork;
import android.telephony.CellIdentity;
import android.telephony.CellIdentityCdma;
import android.telephony.CellIdentityGsm;
import android.telephony.CellIdentityLte;
import android.telephony.CellIdentityWcdma;
import android.telephony.CellInfo;
import android.telephony.CellInfoCdma;
import android.telephony.CellInfoGsm;
import android.telephony.CellInfoLte;
import android.telephony.CellInfoWcdma;
import android.text.BidiFormatter;
import android.text.TextDirectionHeuristics;
import android.text.TextUtils;
import android.util.Log;
import com.android.internal.telephony.OperatorInfo;
import java.util.List;
/**
* Add static Utility functions to get information from the CellInfo object.
* TODO: Modify {@link CellInfo} for simplify those functions
*/
public final class CellInfoUtil {
private static final String TAG = "NetworkSelectSetting";
private CellInfoUtil() {
}
/**
* Wrap a CellIdentity into a CellInfo.
*/
public static CellInfo wrapCellInfoWithCellIdentity(CellIdentity cellIdentity) {
if (cellIdentity instanceof CellIdentityLte) {
CellInfoLte cellInfo = new CellInfoLte();
cellInfo.setCellIdentity((CellIdentityLte) cellIdentity);
return cellInfo;
} else if (cellIdentity instanceof CellIdentityCdma) {
CellInfoCdma cellInfo = new CellInfoCdma();
cellInfo.setCellIdentity((CellIdentityCdma) cellIdentity);
return cellInfo;
} else if (cellIdentity instanceof CellIdentityWcdma) {
CellInfoWcdma cellInfo = new CellInfoWcdma();
cellInfo.setCellIdentity((CellIdentityWcdma) cellIdentity);
return cellInfo;
} else if (cellIdentity instanceof CellIdentityGsm) {
CellInfoGsm cellInfo = new CellInfoGsm();
cellInfo.setCellIdentity((CellIdentityGsm) cellIdentity);
return cellInfo;
} else {
Log.e(TAG, "Invalid CellInfo type");
return null;
}
}
/**
* Returns the title of the network obtained in the manual search.
*
* @param cellInfo contains the information of the network.
* @return Long Name if not null/empty, otherwise Short Name if not null/empty,
* else MCCMNC string.
*/
public static String getNetworkTitle(CellInfo cellInfo) {
OperatorInfo oi = getOperatorInfoFromCellInfo(cellInfo);
if (!TextUtils.isEmpty(oi.getOperatorAlphaLong())) {
return oi.getOperatorAlphaLong();
} else if (!TextUtils.isEmpty(oi.getOperatorAlphaShort())) {
return oi.getOperatorAlphaShort();
} else {
BidiFormatter bidiFormatter = BidiFormatter.getInstance();
return bidiFormatter.unicodeWrap(oi.getOperatorNumeric(), TextDirectionHeuristics.LTR);
}
}
/**
* Wrap a cell info into an operator info.
*/
public static OperatorInfo getOperatorInfoFromCellInfo(CellInfo cellInfo) {
OperatorInfo oi;
if (cellInfo instanceof CellInfoLte) {
CellInfoLte lte = (CellInfoLte) cellInfo;
oi = new OperatorInfo(
(String) lte.getCellIdentity().getOperatorAlphaLong(),
(String) lte.getCellIdentity().getOperatorAlphaShort(),
lte.getCellIdentity().getMobileNetworkOperator());
} else if (cellInfo instanceof CellInfoWcdma) {
CellInfoWcdma wcdma = (CellInfoWcdma) cellInfo;
oi = new OperatorInfo(
(String) wcdma.getCellIdentity().getOperatorAlphaLong(),
(String) wcdma.getCellIdentity().getOperatorAlphaShort(),
wcdma.getCellIdentity().getMobileNetworkOperator());
} else if (cellInfo instanceof CellInfoGsm) {
CellInfoGsm gsm = (CellInfoGsm) cellInfo;
oi = new OperatorInfo(
(String) gsm.getCellIdentity().getOperatorAlphaLong(),
(String) gsm.getCellIdentity().getOperatorAlphaShort(),
gsm.getCellIdentity().getMobileNetworkOperator());
} else if (cellInfo instanceof CellInfoCdma) {
CellInfoCdma cdma = (CellInfoCdma) cellInfo;
oi = new OperatorInfo(
(String) cdma.getCellIdentity().getOperatorAlphaLong(),
(String) cdma.getCellIdentity().getOperatorAlphaShort(),
"" /* operator numeric */);
} else {
Log.e(TAG, "Invalid CellInfo type");
oi = new OperatorInfo("", "", "");
}
return oi;
}
/** Checks whether the network operator is forbidden. */
public static boolean isForbidden(CellInfo cellInfo, List<String> forbiddenPlmns) {
String plmn = CellInfoUtil.getOperatorInfoFromCellInfo(cellInfo).getOperatorNumeric();
return forbiddenPlmns != null && forbiddenPlmns.contains(plmn);
}
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright (C) 2018 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.mobilenetwork;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.telephony.CellInfo;
import android.telephony.SignalStrength;
import android.util.Log;
import android.view.Gravity;
import com.android.settings.R;
import com.android.settingslib.graph.SignalDrawable;
import java.util.List;
import androidx.preference.Preference;
/**
* A Preference represents a network operator in the NetworkSelectSetting fragment.
*/
public class NetworkOperatorPreference extends Preference {
private static final String TAG = "NetworkOperatorPref";
private static final boolean DBG = false;
// number of signal strength level
public static final int NUMBER_OF_LEVELS = SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
private CellInfo mCellInfo;
private List<String> mForbiddenPlmns;
private int mLevel = -1;
// The following constants are used to draw signal icon.
private static final Drawable EMPTY_DRAWABLE = new ColorDrawable(Color.TRANSPARENT);
private static final int NO_CELL_DATA_CONNECTED_ICON = 0;
public NetworkOperatorPreference(
CellInfo cellinfo, Context context, List<String> forbiddenPlmns) {
super(context);
mCellInfo = cellinfo;
mForbiddenPlmns = forbiddenPlmns;
refresh();
}
public CellInfo getCellInfo() {
return mCellInfo;
}
/**
* Refresh the NetworkOperatorPreference by updating the title and the icon.
*/
public void refresh() {
if (DBG) Log.d(TAG, "refresh the network: " + CellInfoUtil.getNetworkTitle(mCellInfo));
String networkTitle = CellInfoUtil.getNetworkTitle(mCellInfo);
if (CellInfoUtil.isForbidden(mCellInfo, mForbiddenPlmns)) {
networkTitle += " " + getContext().getResources().getString(R.string.forbidden_network);
}
setTitle(networkTitle);
int level = mCellInfo.getCellSignalStrength().getLevel();
if (DBG) Log.d(TAG, "refresh level: " + String.valueOf(level));
if (mLevel != level) {
mLevel = level;
updateIcon(mLevel);
}
}
/**
* Update the icon according to the input signal strength level.
*/
public void setIcon(int level) {
updateIcon(level);
}
private static int getIconIdForCell(CellInfo ci) {
final int type = ci.getCellIdentity().getType();
switch (type) {
case CellInfo.TYPE_GSM: return R.drawable.signal_strength_g;
case CellInfo.TYPE_WCDMA: // fall through
case CellInfo.TYPE_TDSCDMA: return R.drawable.signal_strength_3g;
case CellInfo.TYPE_LTE: return R.drawable.signal_strength_lte;
case CellInfo.TYPE_CDMA: return R.drawable.signal_strength_1x;
default: return 0;
}
}
private void updateIcon(int level) {
if (level < 0 || level >= NUMBER_OF_LEVELS) return;
Context context = getContext();
// Make the signal strength drawable
int iconId = 0;
if (DBG) Log.d(TAG, "updateIcon level: " + String.valueOf(level));
iconId = SignalDrawable.getState(level, NUMBER_OF_LEVELS, false /* cutOut */);
SignalDrawable signalDrawable = new SignalDrawable(getContext());
signalDrawable.setLevel(iconId);
signalDrawable.setDarkIntensity(0);
// Make the network type drawable
int iconType = getIconIdForCell(mCellInfo);
Drawable networkDrawable =
iconType == NO_CELL_DATA_CONNECTED_ICON
? EMPTY_DRAWABLE
: getContext()
.getResources().getDrawable(iconType, getContext().getTheme());
// Overlay the two drawables
Drawable[] layers = {networkDrawable, signalDrawable};
final int iconSize =
context.getResources().getDimensionPixelSize(R.dimen.signal_strength_icon_size);
LayerDrawable icons = new LayerDrawable(layers);
// Set the network type icon at the top left
icons.setLayerGravity(0 /* index of networkDrawable */, Gravity.TOP | Gravity.LEFT);
// Set the signal strength icon at the bottom right
icons.setLayerGravity(1 /* index of SignalDrawable */, Gravity.BOTTOM | Gravity.RIGHT);
icons.setLayerSize(1 /* index of SignalDrawable */, iconSize, iconSize);
setIcon(icons);
}
}

View File

@@ -0,0 +1,557 @@
/*
* Copyright (C) 2018 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.mobilenetwork;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.SearchIndexableResource;
import android.telephony.AccessNetworkConstants;
import android.telephony.CellIdentity;
import android.telephony.CellInfo;
import android.telephony.NetworkRegistrationState;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.View;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.telephony.OperatorInfo;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.utils.ThreadUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
/**
* "Choose network" settings UI for the Phone app.
*/
//TODO(b/115429509): Add test for this file once b/115429509 is not blocked anymore
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class NetworkSelectSettings extends DashboardFragment {
private static final String TAG = "NetworkSelectSetting";
private static final boolean DBG = true;
public static final String KEY_SUBSCRIPTION_ID = "subscription_id";
private static final int EVENT_SET_NETWORK_SELECTION_MANUALLY_DONE = 1;
private static final int EVENT_NETWORK_SCAN_RESULTS = 2;
private static final int EVENT_NETWORK_SCAN_ERROR = 3;
private static final int EVENT_NETWORK_SCAN_COMPLETED = 4;
private static final String PREF_KEY_CONNECTED_NETWORK_OPERATOR =
"connected_network_operator_preference";
private static final String PREF_KEY_NETWORK_OPERATORS = "network_operators_preference";
// used to add/remove NetworkOperatorsPreference.
private PreferenceCategory mNetworkOperatorsPreferences;
// used to add/remove connected NetworkOperatorPreference.
private PreferenceCategory mConnectedNetworkOperatorsPreference;
// manage the progress bar on the top of the page.
private View mProgressHeader;
private Preference mStatusMessagePreference;
private List<CellInfo> mCellInfoList;
private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private NetworkOperatorPreference mSelectedNetworkOperatorPreference;
private TelephonyManager mTelephonyManager;
private List<String> mForbiddenPlmns;
//Flag indicating whether we have called bind on the service.
private boolean mShouldUnbind;
private final Runnable mUpdateNetworkOperatorsRunnable = () -> {
updateNetworkOperatorsPreferenceCategory();
};
/**
* Create a new instance of this fragment.
*/
public static NetworkSelectSettings newInstance(int subId) {
Bundle args = new Bundle();
args.putInt(KEY_SUBSCRIPTION_ID, subId);
NetworkSelectSettings
fragment = new NetworkSelectSettings();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle icicle) {
if (DBG) logd("onCreate");
super.onCreate(icicle);
mSubId = getArguments().getInt(KEY_SUBSCRIPTION_ID);
mConnectedNetworkOperatorsPreference =
(PreferenceCategory) findPreference(PREF_KEY_CONNECTED_NETWORK_OPERATOR);
mNetworkOperatorsPreferences =
(PreferenceCategory) findPreference(PREF_KEY_NETWORK_OPERATORS);
mStatusMessagePreference = new Preference(getContext());
mSelectedNetworkOperatorPreference = null;
mTelephonyManager = TelephonyManager.from(getContext()).createForSubscriptionId(mSubId);
setRetainInstance(true);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mProgressHeader = setPinnedHeaderView(R.layout.wifi_progress_header)
.findViewById(R.id.progress_bar_animation);
setProgressBarVisible(false);
forceConfigConnectedNetworkOperatorsPreferenceCategory();
}
@Override
public void onStart() {
super.onStart();
new AsyncTask<Void, Void, List<String>>() {
@Override
protected List<String> doInBackground(Void... voids) {
String[] forbiddenPlmns = mTelephonyManager.getForbiddenPlmns();
return forbiddenPlmns != null ? Arrays.asList(forbiddenPlmns) : null;
}
@Override
protected void onPostExecute(List<String> result) {
mForbiddenPlmns = result;
bindNetworkQueryService();
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
/**
* Invoked on each preference click in this hierarchy, overrides
* PreferenceActivity's implementation. Used to make sure we track the
* preference click events.
* Since the connected network operator is either faked (when no data connection) or already
* connected, we do not allow user to click the connected network operator.
*/
@Override
public boolean onPreferenceTreeClick(Preference preference) {
if (DBG) logd("User clicked the screen");
stopNetworkQuery();
setProgressBarVisible(false);
if (preference instanceof NetworkOperatorPreference) {
// Refresh the last selected item in case users reselect network.
if (mSelectedNetworkOperatorPreference != null) {
mSelectedNetworkOperatorPreference.setSummary("");
}
mSelectedNetworkOperatorPreference = (NetworkOperatorPreference) preference;
CellInfo cellInfo = mSelectedNetworkOperatorPreference.getCellInfo();
if (DBG) logd("User click a NetworkOperatorPreference: " + cellInfo.toString());
// Send metrics event
MetricsLogger.action(getContext(),
MetricsEvent.ACTION_MOBILE_NETWORK_MANUAL_SELECT_NETWORK);
// Connect to the network
if (SubscriptionManager.isValidSubscriptionId(mSubId)) {
if (DBG) {
logd("Connect to the network: " + CellInfoUtil.getNetworkTitle(cellInfo));
}
// Set summary as "Connecting" to the selected network.
mSelectedNetworkOperatorPreference.setSummary(R.string.network_connecting);
// Set summary as "Disconnected" to the previously connected network
if (mConnectedNetworkOperatorsPreference.getPreferenceCount() > 0) {
NetworkOperatorPreference connectedNetworkOperator = (NetworkOperatorPreference)
(mConnectedNetworkOperatorsPreference.getPreference(0));
if (!CellInfoUtil.getNetworkTitle(cellInfo).equals(
CellInfoUtil.getNetworkTitle(connectedNetworkOperator.getCellInfo()))) {
connectedNetworkOperator.setSummary(R.string.network_disconnected);
}
}
OperatorInfo operatorInfo = CellInfoUtil.getOperatorInfoFromCellInfo(cellInfo);
if (DBG) logd("manually selected network operator: " + operatorInfo.toString());
ThreadUtils.postOnBackgroundThread(() -> {
Message msg = mHandler.obtainMessage(EVENT_SET_NETWORK_SELECTION_MANUALLY_DONE);
msg.obj = mTelephonyManager.setNetworkSelectionModeManual(
operatorInfo.getOperatorNumeric(), true /* persistSelection */);
msg.sendToTarget();
});
setProgressBarVisible(true);
return true;
} else {
loge("Error selecting network. Subscription Id is invalid.");
mSelectedNetworkOperatorPreference = null;
return false;
}
} else {
getPreferenceScreen().setEnabled(false);
return false;
}
}
@Override
public void onStop() {
super.onStop();
if (DBG) logd("onStop");
getView().removeCallbacks(mUpdateNetworkOperatorsRunnable);
stopNetworkQuery();
// Unbind the NetworkQueryService
unbindNetworkQueryService();
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.choose_network;
}
@Override
protected String getLogTag() {
return TAG;
}
@Override
public int getMetricsCategory() {
//TODO(b/114749736): add metrics id for this page
return 0;
}
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_SET_NETWORK_SELECTION_MANUALLY_DONE:
if (DBG) logd("network selection done: hide the progress header");
setProgressBarVisible(false);
boolean isSuccessed = (boolean) msg.obj;
if (isSuccessed) {
if (DBG) logd("manual network selection: succeeded! ");
// Set summary as "Connected" to the selected network.
mSelectedNetworkOperatorPreference.setSummary(R.string.network_connected);
} else {
if (DBG) logd("manual network selection: failed! ");
updateNetworkSelection();
// Set summary as "Couldn't connect" to the selected network.
mSelectedNetworkOperatorPreference.setSummary(
R.string.network_could_not_connect);
}
break;
case EVENT_NETWORK_SCAN_RESULTS:
List<CellInfo> results = aggregateCellInfoList((List<CellInfo>) msg.obj);
mCellInfoList = new ArrayList<>(results);
if (DBG) logd("after aggregate: " + mCellInfoList.toString());
if (mCellInfoList != null && mCellInfoList.size() != 0) {
updateNetworkOperators();
} else {
addMessagePreference(R.string.empty_networks_list);
}
break;
case EVENT_NETWORK_SCAN_ERROR:
int error = msg.arg1;
if (DBG) logd("error while querying available networks " + error);
stopNetworkQuery();
addMessagePreference(R.string.network_query_error);
break;
case EVENT_NETWORK_SCAN_COMPLETED:
stopNetworkQuery();
if (DBG) logd("scan complete");
if (mCellInfoList == null) {
// In case the scan timeout before getting any results
addMessagePreference(R.string.empty_networks_list);
}
break;
}
return;
}
};
private void updateNetworkOperators() {
if (DBG) logd("updateNetworkOperators");
if (getActivity() != null) {
final View view = getView();
final Handler handler = view.getHandler();
if (handler != null && handler.hasCallbacks(mUpdateNetworkOperatorsRunnable)) {
return;
}
view.post(mUpdateNetworkOperatorsRunnable);
}
}
/**
* Update the currently available network operators list, which only contains the unregistered
* network operators. So if the device has no data and the network operator in the connected
* network operator category shows "Disconnected", it will also exist in the available network
* operator category for user to select. On the other hand, if the device has data and the
* network operator in the connected network operator category shows "Connected", it will not
* exist in the available network category.
*/
private void updateNetworkOperatorsPreferenceCategory() {
mNetworkOperatorsPreferences.removeAll();
configConnectedNetworkOperatorsPreferenceCategory();
for (int index = 0; index < mCellInfoList.size(); index++) {
if (!mCellInfoList.get(index).isRegistered()) {
NetworkOperatorPreference pref = new NetworkOperatorPreference(
mCellInfoList.get(index), getContext(), mForbiddenPlmns);
pref.setKey(CellInfoUtil.getNetworkTitle(mCellInfoList.get(index)));
pref.setOrder(index);
mNetworkOperatorsPreferences.addPreference(pref);
}
}
}
/**
* Config the connected network operator preference when the page was created. When user get
* into this page, the device might or might not have data connection.
* - If the device has data:
* 1. use {@code ServiceState#getNetworkRegistrationStates()} to get the currently
* registered cellIdentity, wrap it into a CellInfo;
* 2. set the signal strength level as strong;
* 3. use {@link TelephonyManager#getNetworkOperatorName()} to get the title of the
* previously connected network operator, since the CellIdentity got from step 1 only has
* PLMN.
* - If the device has no data, we will remove the connected network operators list from the
* screen.
*/
private void forceConfigConnectedNetworkOperatorsPreferenceCategory() {
if (DBG) logd("Force config ConnectedNetworkOperatorsPreferenceCategory");
if (mTelephonyManager.getDataState() == mTelephonyManager.DATA_CONNECTED) {
// Try to get the network registration states
ServiceState ss = mTelephonyManager.getServiceState();
List<NetworkRegistrationState> networkList =
ss.getNetworkRegistrationStates(AccessNetworkConstants.TransportType.WWAN);
if (networkList == null || networkList.size() == 0) {
loge("getNetworkRegistrationStates return null");
// Remove the connected network operators category
removeConnectedNetworkOperatorPreference();
return;
}
CellIdentity cellIdentity = networkList.get(0).getCellIdentity();
CellInfo cellInfo = CellInfoUtil.wrapCellInfoWithCellIdentity(cellIdentity);
if (cellInfo != null) {
if (DBG) logd("Currently registered cell: " + cellInfo.toString());
NetworkOperatorPreference pref =
new NetworkOperatorPreference(cellInfo, getContext(), mForbiddenPlmns);
pref.setTitle(mTelephonyManager.getNetworkOperatorName());
pref.setSummary(R.string.network_connected);
// Update the signal strength icon, since the default signalStrength value would be
// zero (it would be quite confusing why the connected network has no signal)
pref.setIcon(NetworkOperatorPreference.NUMBER_OF_LEVELS - 1);
mConnectedNetworkOperatorsPreference.addPreference(pref);
} else {
loge("Invalid CellIfno: " + cellInfo.toString());
// Remove the connected network operators category
removeConnectedNetworkOperatorPreference();
}
} else {
if (DBG) logd("No currently registered cell");
// Remove the connected network operators category
removeConnectedNetworkOperatorPreference();
}
}
/**
* Configure the ConnectedNetworkOperatorsPreferenceCategory. The category only need to be
* configured if the category is currently empty or the operator network title of the previous
* connected network is different from the new one.
*/
private void configConnectedNetworkOperatorsPreferenceCategory() {
if (DBG) logd("config ConnectedNetworkOperatorsPreferenceCategory");
// Remove the category if the CellInfo list is empty or does not have registered cell.
if (mCellInfoList.size() == 0) {
if (DBG) logd("empty cellinfo list");
removeConnectedNetworkOperatorPreference();
}
CellInfo connectedNetworkOperator = null;
for (CellInfo cellInfo : mCellInfoList) {
if (cellInfo.isRegistered()) {
connectedNetworkOperator = cellInfo;
break;
}
}
if (connectedNetworkOperator == null) {
if (DBG) logd("no registered network");
removeConnectedNetworkOperatorPreference();
return;
}
// config the category if it is empty.
if (mConnectedNetworkOperatorsPreference.getPreferenceCount() == 0) {
if (DBG) logd("ConnectedNetworkSelectList is empty, add one");
addConnectedNetworkOperatorPreference(connectedNetworkOperator);
return;
}
NetworkOperatorPreference previousConnectedNetworkOperator = (NetworkOperatorPreference)
(mConnectedNetworkOperatorsPreference.getPreference(0));
// config the category if the network title of the previous connected network is different
// from the new one.
String cTitle = CellInfoUtil.getNetworkTitle(connectedNetworkOperator);
String pTitle = CellInfoUtil.getNetworkTitle(
previousConnectedNetworkOperator.getCellInfo());
if (!cTitle.equals(pTitle)) {
if (DBG) logd("reconfig the category: connected network changed");
addConnectedNetworkOperatorPreference(connectedNetworkOperator);
return;
}
if (DBG) logd("same network operator is connected, only refresh the connected network");
// Otherwise same network operator is connected, only refresh the connected network
// operator preference (first and the only one in this category).
((NetworkOperatorPreference) mConnectedNetworkOperatorsPreference.getPreference(0))
.refresh();
return;
}
/**
* Creates a Preference for the given {@link CellInfo} and adds it to the
* {@link #mConnectedNetworkOperatorsPreference}.
*/
private void addConnectedNetworkOperatorPreference(CellInfo cellInfo) {
if (DBG) logd("addConnectedNetworkOperatorPreference");
// Remove the current ConnectedNetworkOperatorsPreference
removeConnectedNetworkOperatorPreference();
final NetworkOperatorPreference pref =
new NetworkOperatorPreference(cellInfo, getContext(), mForbiddenPlmns);
pref.setSummary(R.string.network_connected);
mConnectedNetworkOperatorsPreference.addPreference(pref);
PreferenceScreen preferenceScreen = getPreferenceScreen();
preferenceScreen.addPreference(mConnectedNetworkOperatorsPreference);
}
/** Removes all preferences and hide the {@link #mConnectedNetworkOperatorsPreference}. */
private void removeConnectedNetworkOperatorPreference() {
mConnectedNetworkOperatorsPreference.removeAll();
PreferenceScreen preferenceScreen = getPreferenceScreen();
preferenceScreen.removePreference(mConnectedNetworkOperatorsPreference);
}
protected void setProgressBarVisible(boolean visible) {
if (mProgressHeader != null) {
mProgressHeader.setVisibility(visible ? View.VISIBLE : View.GONE);
}
}
private void addMessagePreference(int messageId) {
if (DBG) logd("remove callback");
getView().removeCallbacks(mUpdateNetworkOperatorsRunnable);
setProgressBarVisible(false);
if (DBG) logd("addMessagePreference");
mStatusMessagePreference.setTitle(messageId);
removeConnectedNetworkOperatorPreference();
mNetworkOperatorsPreferences.removeAll();
mNetworkOperatorsPreferences.addPreference(mStatusMessagePreference);
}
/**
* The Scan results may contains several cell infos with different radio technologies and signal
* strength for one network operator. Aggregate the CellInfoList by retaining only the cell info
* with the strongest signal strength.
*/
private List<CellInfo> aggregateCellInfoList(List<CellInfo> cellInfoList) {
if (DBG) logd("before aggregate: " + cellInfoList.toString());
Map<String, CellInfo> map = new HashMap<>();
for (CellInfo cellInfo : cellInfoList) {
String plmn = CellInfoUtil.getOperatorInfoFromCellInfo(cellInfo).getOperatorNumeric();
if (cellInfo.isRegistered() || !map.containsKey(plmn)) {
map.put(plmn, cellInfo);
} else {
if (map.get(plmn).isRegistered()
|| map.get(plmn).getCellSignalStrength().getLevel()
> cellInfo.getCellSignalStrength().getLevel()) {
// Skip if the stored cellInfo is registered or has higher signal strength level
continue;
}
// Otherwise replace it with the new CellInfo
map.put(plmn, cellInfo);
}
}
return new ArrayList<>(map.values());
}
private void loadNetworksList() {
if (DBG) logd("load networks list...");
setProgressBarVisible(true);
//TODO(b/114749736): load network list once b/115401728 is done
}
private void bindNetworkQueryService() {
if (DBG) logd("bindNetworkQueryService");
//TODO(b/114749736): bind service/manager once b/115401728 is done
mShouldUnbind = true;
}
private void unbindNetworkQueryService() {
if (DBG) logd("unbindNetworkQueryService");
if (mShouldUnbind) {
if (DBG) logd("mShouldUnbind is true");
// unbind the service.
//TODO(b/114749736): unbind service/manager once b/115401728 is done
mShouldUnbind = false;
}
}
private void updateNetworkSelection() {
if (DBG) logd("Update notification about no service of user selected operator");
//TODO(b/114749736): update network selection once b/115429509 is done
}
private void stopNetworkQuery() {
// Stop the network query process
//TODO(b/114749736): stop service/manager query once b/115401728 is done
}
private void logd(String msg) {
Log.d(TAG, msg);
}
private void loge(String msg) {
Log.e(TAG, msg);
}
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
boolean enabled) {
final ArrayList<SearchIndexableResource> result = new ArrayList<>();
final SearchIndexableResource sir = new SearchIndexableResource(context);
sir.xmlResId = R.xml.choose_network;
result.add(sir);
return result;
}
};
}