Bug: 349681531 Flag: EXEMPT migration Test: visual Change-Id: I511d2b3e183472a12fdd07a293eda4c04617bc6c
352 lines
12 KiB
Java
352 lines
12 KiB
Java
/*
|
|
* Copyright (C) 2021 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.wifi;
|
|
|
|
import static com.android.settingslib.wifi.WifiUtils.getHotspotIconResource;
|
|
|
|
import android.content.Context;
|
|
import android.content.res.Resources;
|
|
import android.content.res.TypedArray;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.graphics.drawable.StateListDrawable;
|
|
import android.text.TextUtils;
|
|
import android.view.View;
|
|
import android.widget.ImageButton;
|
|
import android.widget.ImageView;
|
|
import android.widget.LinearLayout;
|
|
import android.widget.TextView;
|
|
|
|
import androidx.annotation.DrawableRes;
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
import androidx.annotation.VisibleForTesting;
|
|
import androidx.preference.PreferenceViewHolder;
|
|
|
|
import com.android.settingslib.R;
|
|
import com.android.settingslib.RestrictedPreference;
|
|
import com.android.settingslib.Utils;
|
|
import com.android.settingslib.widget.SettingsThemeHelper;
|
|
import com.android.settingslib.wifi.WifiUtils;
|
|
import com.android.wifitrackerlib.HotspotNetworkEntry;
|
|
import com.android.wifitrackerlib.WifiEntry;
|
|
|
|
/**
|
|
* Preference to display a WifiEntry in a wifi picker.
|
|
*/
|
|
public class WifiEntryPreference extends RestrictedPreference implements
|
|
WifiEntry.WifiEntryCallback,
|
|
View.OnClickListener {
|
|
|
|
private static final int[] STATE_SECURED = {
|
|
R.attr.state_encrypted
|
|
};
|
|
|
|
private static final int[] FRICTION_ATTRS = {
|
|
R.attr.wifi_friction
|
|
};
|
|
|
|
// These values must be kept within [WifiEntry.WIFI_LEVEL_MIN, WifiEntry.WIFI_LEVEL_MAX]
|
|
private static final int[] WIFI_CONNECTION_STRENGTH = {
|
|
R.string.accessibility_no_wifi,
|
|
R.string.accessibility_wifi_one_bar,
|
|
R.string.accessibility_wifi_two_bars,
|
|
R.string.accessibility_wifi_three_bars,
|
|
R.string.accessibility_wifi_signal_full
|
|
};
|
|
|
|
// StateListDrawable to display secured lock / metered "$" icon
|
|
@Nullable private final StateListDrawable mFrictionSld;
|
|
private final WifiUtils.InternetIconInjector mIconInjector;
|
|
private WifiEntry mWifiEntry;
|
|
private int mLevel = -1;
|
|
private boolean mShowX; // Shows the Wi-Fi signl icon of Pie+x when it's true.
|
|
private CharSequence mContentDescription;
|
|
private OnButtonClickListener mOnButtonClickListener;
|
|
|
|
public WifiEntryPreference(@NonNull Context context, @NonNull WifiEntry wifiEntry) {
|
|
this(context, wifiEntry, new WifiUtils.InternetIconInjector(context));
|
|
}
|
|
|
|
@VisibleForTesting
|
|
WifiEntryPreference(@NonNull Context context, @NonNull WifiEntry wifiEntry,
|
|
@NonNull WifiUtils.InternetIconInjector iconInjector) {
|
|
super(context);
|
|
|
|
setLayoutResource(R.layout.preference_access_point);
|
|
mFrictionSld = getFrictionStateListDrawable();
|
|
mIconInjector = iconInjector;
|
|
setWifiEntry(wifiEntry);
|
|
}
|
|
|
|
/**
|
|
* Set updated {@link WifiEntry} to refresh the preference
|
|
*
|
|
* @param wifiEntry An instance of {@link WifiEntry}
|
|
*/
|
|
public void setWifiEntry(@NonNull WifiEntry wifiEntry) {
|
|
mWifiEntry = wifiEntry;
|
|
mWifiEntry.setListener(this);
|
|
refresh();
|
|
}
|
|
|
|
public WifiEntry getWifiEntry() {
|
|
return mWifiEntry;
|
|
}
|
|
|
|
@Override
|
|
public void onBindViewHolder(final PreferenceViewHolder view) {
|
|
super.onBindViewHolder(view);
|
|
if (mWifiEntry.isVerboseSummaryEnabled()) {
|
|
TextView summary = (TextView) view.findViewById(android.R.id.summary);
|
|
if (summary != null) {
|
|
summary.setMaxLines(100);
|
|
}
|
|
}
|
|
final Drawable drawable = getIcon();
|
|
if (drawable != null) {
|
|
drawable.setLevel(mLevel);
|
|
}
|
|
|
|
view.itemView.setContentDescription(mContentDescription);
|
|
|
|
// Turn off divider
|
|
view.findViewById(com.android.settingslib.widget.preference.twotarget.R.id.two_target_divider)
|
|
.setVisibility(View.INVISIBLE);
|
|
|
|
// Set padding to expressive style
|
|
if (SettingsThemeHelper.isExpressiveTheme(getContext())) {
|
|
final int paddingStart = getContext().getResources().getDimensionPixelSize(
|
|
com.android.settingslib.widget.theme
|
|
.R.dimen.settingslib_expressive_space_extrasmall4);
|
|
final int paddingEnd = getContext().getResources().getDimensionPixelSize(
|
|
com.android.settingslib.widget.theme
|
|
.R.dimen.settingslib_expressive_space_small3);
|
|
LinearLayout iconFrame = (LinearLayout) view.findViewById(
|
|
com.android.settingslib.R.id.icon_frame);
|
|
iconFrame.setPaddingRelative(paddingStart, iconFrame.getPaddingTop(),
|
|
paddingEnd, iconFrame.getPaddingBottom());
|
|
}
|
|
|
|
// Enable the icon button when the help string in this WifiEntry is not null.
|
|
final ImageButton imageButton = (ImageButton) view.findViewById(R.id.icon_button);
|
|
final ImageView frictionImageView = (ImageView) view.findViewById(
|
|
R.id.friction_icon);
|
|
if (mWifiEntry.getHelpUriString() != null
|
|
&& mWifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_DISCONNECTED) {
|
|
final Drawable drawablehelp = getDrawable(R.drawable.ic_help);
|
|
drawablehelp.setTintList(
|
|
Utils.getColorAttr(getContext(), android.R.attr.colorControlNormal));
|
|
((ImageView) imageButton).setImageDrawable(drawablehelp);
|
|
imageButton.setVisibility(View.VISIBLE);
|
|
imageButton.setOnClickListener(this);
|
|
imageButton.setContentDescription(
|
|
getContext().getText(R.string.help_label));
|
|
|
|
if (frictionImageView != null) {
|
|
frictionImageView.setVisibility(View.GONE);
|
|
}
|
|
} else {
|
|
imageButton.setVisibility(View.GONE);
|
|
|
|
if (frictionImageView != null) {
|
|
frictionImageView.setVisibility(View.VISIBLE);
|
|
bindFrictionImage(frictionImageView);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates the title and summary; may indirectly call notifyChanged().
|
|
*/
|
|
public void refresh() {
|
|
setTitle(mWifiEntry.getTitle());
|
|
if (mWifiEntry instanceof HotspotNetworkEntry) {
|
|
updateHotspotIcon(((HotspotNetworkEntry) mWifiEntry).getDeviceType());
|
|
} else {
|
|
mLevel = mWifiEntry.getLevel();
|
|
mShowX = mWifiEntry.shouldShowXLevelIcon();
|
|
updateIcon(mShowX, mLevel);
|
|
}
|
|
|
|
setSummary(mWifiEntry.getSummary(false /* concise */));
|
|
mContentDescription = buildContentDescription();
|
|
}
|
|
|
|
/**
|
|
* Indicates the state of the WifiEntry has changed and clients may retrieve updates through
|
|
* the WifiEntry getter methods.
|
|
*/
|
|
public void onUpdated() {
|
|
// TODO(b/70983952): Fill this method in
|
|
refresh();
|
|
}
|
|
|
|
/**
|
|
* Result of the connect request indicated by the WifiEntry.CONNECT_STATUS constants.
|
|
*/
|
|
public void onConnectResult(int status) {
|
|
// TODO(b/70983952): Fill this method in
|
|
}
|
|
|
|
/**
|
|
* Result of the disconnect request indicated by the WifiEntry.DISCONNECT_STATUS constants.
|
|
*/
|
|
public void onDisconnectResult(int status) {
|
|
// TODO(b/70983952): Fill this method in
|
|
}
|
|
|
|
/**
|
|
* Result of the forget request indicated by the WifiEntry.FORGET_STATUS constants.
|
|
*/
|
|
public void onForgetResult(int status) {
|
|
// TODO(b/70983952): Fill this method in
|
|
}
|
|
|
|
/**
|
|
* Result of the sign-in request indecated by the WifiEntry.SIGNIN_STATUS constants
|
|
*/
|
|
public void onSignInResult(int status) {
|
|
// TODO(b/70983952): Fill this method in
|
|
}
|
|
|
|
protected int getIconColorAttr() {
|
|
final boolean accent = (mWifiEntry.hasInternetAccess()
|
|
&& mWifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED);
|
|
return accent ? android.R.attr.colorAccent : android.R.attr.colorControlNormal;
|
|
}
|
|
|
|
private void setIconWithTint(Drawable drawable) {
|
|
if (drawable != null) {
|
|
// Must use Drawable#setTintList() instead of Drawable#setTint() to show the grey
|
|
// icon when the preference is disabled.
|
|
drawable.setTintList(Utils.getColorAttr(getContext(), getIconColorAttr()));
|
|
setIcon(drawable);
|
|
} else {
|
|
setIcon(null);
|
|
}
|
|
}
|
|
|
|
@VisibleForTesting
|
|
void updateIcon(boolean showX, int level) {
|
|
if (level == -1) {
|
|
setIcon(null);
|
|
return;
|
|
}
|
|
setIconWithTint(mIconInjector.getIcon(showX, level));
|
|
}
|
|
|
|
@VisibleForTesting
|
|
void updateHotspotIcon(int deviceType) {
|
|
setIconWithTint(getContext().getDrawable(getHotspotIconResource(deviceType)));
|
|
}
|
|
|
|
@Nullable
|
|
private StateListDrawable getFrictionStateListDrawable() {
|
|
TypedArray frictionSld;
|
|
try {
|
|
frictionSld = getContext().getTheme().obtainStyledAttributes(FRICTION_ATTRS);
|
|
} catch (Resources.NotFoundException e) {
|
|
// Fallback for platforms that do not need friction icon resources.
|
|
frictionSld = null;
|
|
}
|
|
return frictionSld != null ? (StateListDrawable) frictionSld.getDrawable(0) : null;
|
|
}
|
|
|
|
/**
|
|
* Binds the friction icon drawable using a StateListDrawable.
|
|
*
|
|
* <p>Friction icons will be rebound when notifyChange() is called, and therefore
|
|
* do not need to be managed in refresh()</p>.
|
|
*/
|
|
private void bindFrictionImage(ImageView frictionImageView) {
|
|
if (frictionImageView == null || mFrictionSld == null) {
|
|
return;
|
|
}
|
|
if ((mWifiEntry.getSecurity() != WifiEntry.SECURITY_NONE)
|
|
&& (mWifiEntry.getSecurity() != WifiEntry.SECURITY_OWE)) {
|
|
mFrictionSld.setState(STATE_SECURED);
|
|
}
|
|
frictionImageView.setImageDrawable(mFrictionSld.getCurrent());
|
|
}
|
|
|
|
/**
|
|
* Helper method to generate content description string.
|
|
*/
|
|
@VisibleForTesting
|
|
CharSequence buildContentDescription() {
|
|
final Context context = getContext();
|
|
|
|
CharSequence contentDescription = getTitle();
|
|
final CharSequence summary = getSummary();
|
|
if (!TextUtils.isEmpty(summary)) {
|
|
contentDescription = TextUtils.concat(contentDescription, ",", summary);
|
|
}
|
|
int level = mWifiEntry.getLevel();
|
|
if (level >= 0 && level < WIFI_CONNECTION_STRENGTH.length) {
|
|
contentDescription = TextUtils.concat(contentDescription, ",",
|
|
context.getString(WIFI_CONNECTION_STRENGTH[level]));
|
|
}
|
|
return TextUtils.concat(contentDescription, ",",
|
|
mWifiEntry.getSecurity() == WifiEntry.SECURITY_NONE
|
|
? context.getString(R.string.accessibility_wifi_security_type_none)
|
|
: context.getString(R.string.accessibility_wifi_security_type_secured));
|
|
}
|
|
|
|
/**
|
|
* Set listeners, who want to listen the button client event.
|
|
*/
|
|
public void setOnButtonClickListener(OnButtonClickListener listener) {
|
|
mOnButtonClickListener = listener;
|
|
notifyChanged();
|
|
}
|
|
|
|
@Override
|
|
protected int getSecondTargetResId() {
|
|
return R.layout.access_point_friction_widget;
|
|
}
|
|
|
|
@Override
|
|
public void onClick(View view) {
|
|
if (view.getId() == R.id.icon_button) {
|
|
if (mOnButtonClickListener != null) {
|
|
mOnButtonClickListener.onButtonClick(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Callback to inform the caller that the icon button is clicked.
|
|
*/
|
|
public interface OnButtonClickListener {
|
|
|
|
/**
|
|
* Register to listen the button click event.
|
|
*/
|
|
void onButtonClick(WifiEntryPreference preference);
|
|
}
|
|
|
|
private Drawable getDrawable(@DrawableRes int iconResId) {
|
|
Drawable buttonIcon = null;
|
|
|
|
try {
|
|
buttonIcon = getContext().getDrawable(iconResId);
|
|
} catch (Resources.NotFoundException exception) {
|
|
// Do nothing
|
|
}
|
|
return buttonIcon;
|
|
}
|
|
}
|