Added WifiEntryPreference as WifiEntry version of AccessPointPreference
Added WifiEntryPreference and LongPressWifiEntryPreference to replace AccessPointPreference using WifiEntry instead of AccessPoint. Test: atest WifiEntryPreferenceTest && manual - visual verification with dummy entries. Bug: 70983952 Change-Id: I7234a9371737c32ee8d585c2802e4ce03a36a441
This commit is contained in:
@@ -24,6 +24,7 @@ android_library {
|
||||
"SettingsLibProgressBar",
|
||||
"SettingsLibAdaptiveIcon",
|
||||
"SettingsLibRadioButtonPreference",
|
||||
"WifiTrackerLib",
|
||||
],
|
||||
|
||||
// ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.settingslib.wifi;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
import com.android.wifitrackerlib.WifiEntry;
|
||||
|
||||
/**
|
||||
* WifiEntryPreference that can be long pressed.
|
||||
*/
|
||||
public class LongPressWifiEntryPreference extends WifiEntryPreference {
|
||||
|
||||
private final Fragment mFragment;
|
||||
|
||||
public LongPressWifiEntryPreference(Context context, WifiEntry wifiEntry, Fragment fragment) {
|
||||
super(context, wifiEntry);
|
||||
mFragment = fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final PreferenceViewHolder view) {
|
||||
super.onBindViewHolder(view);
|
||||
if (mFragment != null) {
|
||||
view.itemView.setOnCreateContextMenuListener(mFragment);
|
||||
view.itemView.setTag(this);
|
||||
view.itemView.setLongClickable(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* 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.settingslib.wifi;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
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.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
import com.android.settingslib.R;
|
||||
import com.android.settingslib.Utils;
|
||||
import com.android.wifitrackerlib.WifiEntry;
|
||||
|
||||
/**
|
||||
* Preference to display a WifiEntry in a wifi picker.
|
||||
*/
|
||||
public class WifiEntryPreference extends Preference implements WifiEntry.WifiEntryCallback {
|
||||
|
||||
private static final int[] STATE_SECURED = {
|
||||
R.attr.state_encrypted
|
||||
};
|
||||
|
||||
private static final int[] STATE_METERED = {
|
||||
R.attr.state_metered
|
||||
};
|
||||
|
||||
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 IconInjector mIconInjector;
|
||||
private WifiEntry mWifiEntry;
|
||||
private int mLevel = -1;
|
||||
private CharSequence mContentDescription;
|
||||
|
||||
public WifiEntryPreference(@NonNull Context context, @NonNull WifiEntry wifiEntry) {
|
||||
this(context, wifiEntry, new IconInjector(context));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
WifiEntryPreference(@NonNull Context context, @NonNull WifiEntry wifiEntry,
|
||||
@NonNull IconInjector iconInjector) {
|
||||
super(context);
|
||||
|
||||
setLayoutResource(R.layout.preference_access_point);
|
||||
setWidgetLayoutResource(R.layout.access_point_friction_widget);
|
||||
mFrictionSld = getFrictionStateListDrawable();
|
||||
mWifiEntry = wifiEntry;
|
||||
mWifiEntry.setListener(this);
|
||||
mIconInjector = iconInjector;
|
||||
refresh();
|
||||
}
|
||||
|
||||
public WifiEntry getWifiEntry() {
|
||||
return mWifiEntry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final PreferenceViewHolder view) {
|
||||
super.onBindViewHolder(view);
|
||||
final Drawable drawable = getIcon();
|
||||
if (drawable != null) {
|
||||
drawable.setLevel(mLevel);
|
||||
}
|
||||
|
||||
view.itemView.setContentDescription(mContentDescription);
|
||||
|
||||
final ImageView frictionImageView = (ImageView) view.findViewById(R.id.friction_icon);
|
||||
bindFrictionImage(frictionImageView);
|
||||
|
||||
// Turn off divider
|
||||
view.findViewById(R.id.two_target_divider).setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the title and summary; may indirectly call notifyChanged().
|
||||
*/
|
||||
public void refresh() {
|
||||
setTitle(mWifiEntry.getTitle());
|
||||
final int level = mWifiEntry.getLevel();
|
||||
if (level != mLevel) {
|
||||
mLevel = level;
|
||||
updateIcon(mLevel);
|
||||
notifyChanged();
|
||||
}
|
||||
|
||||
setSummary(mWifiEntry.getSummary());
|
||||
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
|
||||
}
|
||||
|
||||
private void updateIcon(int level) {
|
||||
if (level == -1) {
|
||||
setIcon(null);
|
||||
return;
|
||||
}
|
||||
|
||||
final Drawable drawable = mIconInjector.getIcon(level);
|
||||
if (drawable != null) {
|
||||
drawable.setTintList(Utils.getColorAttr(getContext(),
|
||||
android.R.attr.colorControlNormal));
|
||||
setIcon(drawable);
|
||||
} else {
|
||||
setIcon(null);
|
||||
}
|
||||
}
|
||||
|
||||
@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)
|
||||
&& (mWifiEntry.getSecurity() != WifiEntry.SECURITY_OWE_TRANSITION)) {
|
||||
mFrictionSld.setState(STATE_SECURED);
|
||||
} else if (mWifiEntry.isMetered()) {
|
||||
mFrictionSld.setState(STATE_METERED);
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
static class IconInjector {
|
||||
private final Context mContext;
|
||||
|
||||
IconInjector(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public Drawable getIcon(int level) {
|
||||
return mContext.getDrawable(Utils.getWifiIconResource(level));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* 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.settingslib.wifi;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import com.android.wifitrackerlib.WifiEntry;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class WifiEntryPreferenceTest {
|
||||
|
||||
private Context mContext;
|
||||
|
||||
@Mock
|
||||
private WifiEntry mMockWifiEntry;
|
||||
@Mock
|
||||
private WifiEntryPreference.IconInjector mMockIconInjector;
|
||||
|
||||
@Mock
|
||||
private Drawable mMockDrawable0;
|
||||
@Mock
|
||||
private Drawable mMockDrawable1;
|
||||
@Mock
|
||||
private Drawable mMockDrawable2;
|
||||
@Mock
|
||||
private Drawable mMockDrawable3;
|
||||
@Mock
|
||||
private Drawable mMockDrawable4;
|
||||
|
||||
private static final String MOCK_TITLE = "title";
|
||||
private static final String MOCK_SUMMARY = "summary";
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
when(mMockWifiEntry.getTitle()).thenReturn(MOCK_TITLE);
|
||||
when(mMockWifiEntry.getSummary()).thenReturn(MOCK_SUMMARY);
|
||||
|
||||
when(mMockIconInjector.getIcon(0)).thenReturn(mMockDrawable0);
|
||||
when(mMockIconInjector.getIcon(1)).thenReturn(mMockDrawable1);
|
||||
when(mMockIconInjector.getIcon(2)).thenReturn(mMockDrawable2);
|
||||
when(mMockIconInjector.getIcon(3)).thenReturn(mMockDrawable3);
|
||||
when(mMockIconInjector.getIcon(4)).thenReturn(mMockDrawable4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructor_shouldSetWifiEntryTitleAndSummary() {
|
||||
final WifiEntryPreference pref =
|
||||
new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
|
||||
|
||||
assertThat(pref.getTitle()).isEqualTo(MOCK_TITLE);
|
||||
assertThat(pref.getSummary()).isEqualTo(MOCK_SUMMARY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructor_shouldSetIcon() {
|
||||
when(mMockWifiEntry.getLevel()).thenReturn(0);
|
||||
|
||||
final WifiEntryPreference pref =
|
||||
new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
|
||||
|
||||
assertThat(pref.getIcon()).isEqualTo(mMockDrawable0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void titleChanged_refresh_shouldUpdateTitle() {
|
||||
final WifiEntryPreference pref =
|
||||
new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
|
||||
final String updatedTitle = "updated title";
|
||||
when(mMockWifiEntry.getTitle()).thenReturn(updatedTitle);
|
||||
|
||||
pref.refresh();
|
||||
|
||||
assertThat(pref.getTitle()).isEqualTo(updatedTitle);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void summaryChanged_refresh_shouldUpdateSummary() {
|
||||
final WifiEntryPreference pref =
|
||||
new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
|
||||
final String updatedSummary = "updated summary";
|
||||
when(mMockWifiEntry.getSummary()).thenReturn(updatedSummary);
|
||||
|
||||
pref.refresh();
|
||||
|
||||
assertThat(pref.getSummary()).isEqualTo(updatedSummary);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void levelChanged_refresh_shouldUpdateLevelIcon() {
|
||||
final List<Drawable> iconList = new ArrayList<>();
|
||||
final WifiEntryPreference pref =
|
||||
new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
|
||||
|
||||
when(mMockWifiEntry.getLevel()).thenReturn(0);
|
||||
pref.refresh();
|
||||
iconList.add(pref.getIcon());
|
||||
when(mMockWifiEntry.getLevel()).thenReturn(1);
|
||||
pref.refresh();
|
||||
iconList.add(pref.getIcon());
|
||||
when(mMockWifiEntry.getLevel()).thenReturn(2);
|
||||
pref.refresh();
|
||||
iconList.add(pref.getIcon());
|
||||
when(mMockWifiEntry.getLevel()).thenReturn(3);
|
||||
pref.refresh();
|
||||
iconList.add(pref.getIcon());
|
||||
when(mMockWifiEntry.getLevel()).thenReturn(4);
|
||||
pref.refresh();
|
||||
iconList.add(pref.getIcon());
|
||||
when(mMockWifiEntry.getLevel()).thenReturn(-1);
|
||||
pref.refresh();
|
||||
iconList.add(pref.getIcon());
|
||||
|
||||
assertThat(iconList).containsExactly(mMockDrawable0, mMockDrawable1,
|
||||
mMockDrawable2, mMockDrawable3, mMockDrawable4, null);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user