blob: 32a475a7d00fbaa92a2617129a58f5076b697dda [file] [log] [blame]
/*
* Copyright (C) 2020 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;
import static com.android.settings.network.telephony.MobileNetworkUtils.NO_CELL_DATA_TYPE_ICON;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.telephony.AccessNetworkConstants;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.Html;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.builders.ListBuilder;
import androidx.slice.builders.SliceAction;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.network.telephony.MobileNetworkUtils;
import com.android.settings.slices.CustomSliceable;
import com.android.settings.wifi.slice.WifiSliceItem;
import com.android.settingslib.WirelessUtils;
import com.android.settingslib.net.SignalStrengthUtil;
import com.android.settingslib.utils.ThreadUtils;
import com.android.wifitrackerlib.WifiEntry;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
/**
* The helper is for slice of carrier and non-Carrier, used by ProviderModelSlice.
*/
public class ProviderModelSliceHelper {
private static final String TAG = "ProviderModelSlice";
private final SubscriptionManager mSubscriptionManager;
private TelephonyManager mTelephonyManager;
protected final Context mContext;
private CustomSliceable mSliceable;
public ProviderModelSliceHelper(Context context, CustomSliceable sliceable) {
mContext = context;
mSliceable = sliceable;
mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
mTelephonyManager = context.getSystemService(TelephonyManager.class);
}
/**
* @return whether there is the carrier item in the slice.
*/
public boolean hasCarrier() {
if (isAirplaneModeEnabled()
|| mSubscriptionManager == null || mTelephonyManager == null
|| mSubscriptionManager.getActiveSubscriptionIdList().length <= 0) {
return false;
}
return true;
}
/**
* @return whether the MobileData's is enabled.
*/
public boolean isMobileDataEnabled() {
return mTelephonyManager.isDataEnabled();
}
/**
* To check the carrier data status.
*
* @return whether the carrier data is active.
*/
public boolean isDataSimActive() {
return MobileNetworkUtils.activeNetworkIsCellular(mContext);
}
/**
* @return whether the ServiceState's data state is in-service.
*/
public boolean isDataStateInService() {
final ServiceState serviceState = mTelephonyManager.getServiceState();
NetworkRegistrationInfo regInfo =
(serviceState == null) ? null : serviceState.getNetworkRegistrationInfo(
NetworkRegistrationInfo.DOMAIN_PS,
AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
return (regInfo == null) ? false : regInfo.isRegistered();
}
/**
* @return whether the ServiceState's voice state is in-service.
*/
public boolean isVoiceStateInService() {
final ServiceState serviceState = mTelephonyManager.getServiceState();
return serviceState != null
&& serviceState.getState() == serviceState.STATE_IN_SERVICE;
}
/**
* To get the signal bar icon with level.
*
* @return The Drawable which is a signal bar icon with level.
*/
public Drawable getDrawableWithSignalStrength() {
final SignalStrength strength = mTelephonyManager.getSignalStrength();
int level = (strength == null) ? 0 : strength.getLevel();
int numLevels = SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
if (mSubscriptionManager != null && shouldInflateSignalStrength(
mSubscriptionManager.getDefaultDataSubscriptionId())) {
level += 1;
numLevels += 1;
}
return MobileNetworkUtils.getSignalStrengthIcon(mContext, level, numLevels,
NO_CELL_DATA_TYPE_ICON, false);
}
/**
* To update the telephony with subid.
*/
public void updateTelephony() {
if (mSubscriptionManager == null || mSubscriptionManager.getDefaultDataSubscriptionId()
== mSubscriptionManager.INVALID_SUBSCRIPTION_ID) {
return;
}
mTelephonyManager = mTelephonyManager.createForSubscriptionId(
mSubscriptionManager.getDefaultDataSubscriptionId());
}
protected ListBuilder createListBuilder(Uri uri) {
final ListBuilder builder = new ListBuilder(mContext, uri, ListBuilder.INFINITY)
.setAccentColor(-1)
.setKeywords(getKeywords());
return builder;
}
@Nullable
protected WifiSliceItem getConnectedWifiItem(List<WifiSliceItem> wifiList) {
if (wifiList == null) {
return null;
}
Optional<WifiSliceItem> item = wifiList.stream()
.filter(x -> x.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED)
.findFirst();
return item.isPresent() ? item.get() : null;
}
protected ListBuilder.RowBuilder createCarrierRow(String networkTypeDescription) {
final String title = getMobileTitle();
final String summary = getMobileSummary(networkTypeDescription);
Drawable drawable = mContext.getDrawable(
R.drawable.ic_signal_strength_zero_bar_no_internet);
try {
drawable = getMobileDrawable(drawable);
} catch (Throwable e) {
e.printStackTrace();
}
final IconCompat levelIcon = Utils.createIconWithDrawable(drawable);
final PendingIntent rowIntent = mSliceable.getBroadcastIntent(mContext);
final SliceAction primaryAction = SliceAction.create(rowIntent,
levelIcon, ListBuilder.ICON_IMAGE, title);
final SliceAction toggleAction = SliceAction.createToggle(rowIntent,
"mobile_toggle" /* actionTitle */, isMobileDataEnabled());
final ListBuilder.RowBuilder rowBuilder = new ListBuilder.RowBuilder()
.setTitle(title)
.setTitleItem(levelIcon, ListBuilder.ICON_IMAGE)
.addEndItem(toggleAction)
.setPrimaryAction(primaryAction)
.setSubtitle(Html.fromHtml(summary, Html.FROM_HTML_MODE_LEGACY));
return rowBuilder;
}
protected SliceAction getPrimarySliceAction(String intentAction) {
return SliceAction.createDeeplink(
getPrimaryAction(intentAction),
Utils.createIconWithDrawable(new ColorDrawable(Color.TRANSPARENT)),
ListBuilder.ICON_IMAGE, mContext.getText(R.string.summary_placeholder));
}
protected boolean isAirplaneModeEnabled() {
return WirelessUtils.isAirplaneModeOn(mContext);
}
protected SubscriptionManager getSubscriptionManager() {
return mSubscriptionManager;
}
private static void log(String s) {
Log.d(TAG, s);
}
private PendingIntent getPrimaryAction(String intentAction) {
final Intent intent = new Intent(intentAction)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
return PendingIntent.getActivity(mContext, 0 /* requestCode */,
intent, PendingIntent.FLAG_IMMUTABLE /* flags */);
}
private boolean shouldInflateSignalStrength(int subId) {
return SignalStrengthUtil.shouldInflateSignalStrength(mContext, subId);
}
@VisibleForTesting
Drawable getMobileDrawable(Drawable drawable) throws Throwable {
// set color and drawable
if (mTelephonyManager == null) {
log("mTelephonyManager == null");
return drawable;
}
if (isDataStateInService() || isVoiceStateInService()) {
Semaphore lock = new Semaphore(0);
AtomicReference<Drawable> shared = new AtomicReference<>();
ThreadUtils.postOnMainThread(() -> {
shared.set(getDrawableWithSignalStrength());
lock.release();
});
lock.acquire();
drawable = shared.get();
}
drawable.setTint(
Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorControlNormal));
if (isDataSimActive()) {
drawable.setTint(Utils.getColorAccentDefaultColor(mContext));
}
return drawable;
}
private String getMobileSummary(String networkTypeDescription) {
if (!isMobileDataEnabled()) {
return mContext.getString(R.string.mobile_data_off_summary);
}
if (!isDataStateInService()) {
return mContext.getString(R.string.mobile_data_no_connection);
}
String summary = networkTypeDescription;
if (isDataSimActive()) {
summary = mContext.getString(R.string.preference_summary_default_combination,
mContext.getString(R.string.mobile_data_connection_active),
networkTypeDescription);
}
return summary;
}
protected String getMobileTitle() {
String title = mContext.getText(R.string.mobile_data_settings_title).toString();
if (mSubscriptionManager == null) {
return title;
}
final SubscriptionInfo defaultSubscription = mSubscriptionManager.getActiveSubscriptionInfo(
mSubscriptionManager.getDefaultDataSubscriptionId());
if (defaultSubscription != null) {
title = SubscriptionUtil.getUniqueSubscriptionDisplayName(
defaultSubscription, mContext).toString();
}
return title;
}
private Set<String> getKeywords() {
final String keywords = mContext.getString(R.string.keywords_internet);
return Arrays.stream(TextUtils.split(keywords, ","))
.map(String::trim)
.collect(Collectors.toSet());
}
}