Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0ca645e3 authored by Quang Luong's avatar Quang Luong Committed by Android (Google) Code Review
Browse files

Merge "Remove WifiTrackerLib from SettingsLib"

parents eeacf722 c6fc5b29
Loading
Loading
Loading
Loading
+14 −27
Original line number Diff line number Diff line
@@ -11,33 +11,6 @@ android_library {

    name: "SettingsLib",

    defaults: [
        "SettingsLibDependenciesWithoutWifiTracker",
    ],

    // TODO(b/149540986): revert this change.
    static_libs: [
        // All other dependent components should be put in
        // "SettingsLibDependenciesWithoutWifiTracker".
        "WifiTrackerLib",
    ],

    // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
    // LOCAL_SHARED_JAVA_LIBRARIES := androidx.lifecycle_lifecycle-common

    resource_dirs: ["res"],

    srcs: [
        "src/**/*.java",
        "src/**/*.kt",
    ],

    min_sdk_version: "29",

}

java_defaults {
    name: "SettingsLibDependenciesWithoutWifiTracker",
    static_libs: [
        "androidx.annotation_annotation",
        "androidx.legacy_legacy-support-v4",
@@ -48,6 +21,7 @@ java_defaults {
        "androidx.mediarouter_mediarouter-nodeps",
        "iconloader",

        "WifiTrackerLibRes",
        "SettingsLibHelpUtils",
        "SettingsLibRestrictedLockUtils",
        "SettingsLibActionBarShadow",
@@ -74,6 +48,19 @@ java_defaults {
        "SettingsLibTwoTargetPreference",
        "SettingsLibSettingsTransition",
    ],

    // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
    // LOCAL_SHARED_JAVA_LIBRARIES := androidx.lifecycle_lifecycle-common

    resource_dirs: ["res"],

    srcs: [
        "src/**/*.java",
        "src/**/*.kt",
    ],

    min_sdk_version: "29",

}

// NOTE: Keep this module in sync with ./common.mk
+0 −46
Original line number Diff line number Diff line
/*
 * 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 −314
Original line number Diff line number Diff line
/*
 * 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.ImageButton;
import android.widget.ImageView;

import androidx.annotation.DrawableRes;
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,
        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 IconInjector 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 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);

        // Turn off divider
        view.findViewById(R.id.two_target_divider).setVisibility(View.INVISIBLE);

        // 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());
        final int level = mWifiEntry.getLevel();
        final boolean showX = mWifiEntry.shouldShowXLevelIcon();
        if (level != mLevel || showX != mShowX) {
            mLevel = level;
            mShowX = showX;
            updateIcon(mShowX, mLevel);
            notifyChanged();
        }

        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 updateIcon(boolean showX, int level) {
        if (level == -1) {
            setIcon(null);
            return;
        }

        final Drawable drawable = mIconInjector.getIcon(showX, level);
        if (drawable != null) {
            drawable.setTint(Utils.getColorAttrDefaultColor(getContext(), getIconColorAttr()));
            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)) {
            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));
    }


    static class IconInjector {
        private final Context mContext;

        IconInjector(Context context) {
            mContext = context;
        }

        public Drawable getIcon(boolean showX, int level) {
            return mContext.getDrawable(WifiUtils.getInternetIconResource(level, showX));
        }
    }

    /**
     * Set listeners, who want to listen the button client event.
     */
    public void setOnButtonClickListener(OnButtonClickListener listener) {
        mOnButtonClickListener = listener;
        notifyChanged();
    }

    @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;
    }

}
+0 −254
Original line number Diff line number Diff line
/*
 * 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 android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;

import androidx.preference.PreferenceViewHolder;

import com.android.settingslib.R;
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;

    @Mock
    private Drawable mMockShowXDrawable0;
    @Mock
    private Drawable mMockShowXDrawable1;
    @Mock
    private Drawable mMockShowXDrawable2;
    @Mock
    private Drawable mMockShowXDrawable3;
    @Mock
    private Drawable mMockShowXDrawable4;

    private static final String MOCK_TITLE = "title";
    private static final String MOCK_SUMMARY = "summary";
    private static final String FAKE_URI_STRING = "fakeuri";

    @Before
    public void setUp() {
        mContext = RuntimeEnvironment.application;

        MockitoAnnotations.initMocks(this);

        when(mMockWifiEntry.getTitle()).thenReturn(MOCK_TITLE);
        when(mMockWifiEntry.getSummary(false /* concise */)).thenReturn(MOCK_SUMMARY);

        when(mMockIconInjector.getIcon(false /* showX */, 0)).thenReturn(mMockDrawable0);
        when(mMockIconInjector.getIcon(false /* showX */, 1)).thenReturn(mMockDrawable1);
        when(mMockIconInjector.getIcon(false /* showX */, 2)).thenReturn(mMockDrawable2);
        when(mMockIconInjector.getIcon(false /* showX */, 3)).thenReturn(mMockDrawable3);
        when(mMockIconInjector.getIcon(false /* showX */, 4)).thenReturn(mMockDrawable4);

        when(mMockIconInjector.getIcon(true /* showX */, 0))
                .thenReturn(mMockShowXDrawable0);
        when(mMockIconInjector.getIcon(true /* showX */, 1))
                .thenReturn(mMockShowXDrawable1);
        when(mMockIconInjector.getIcon(true /* showX */, 2))
                .thenReturn(mMockShowXDrawable2);
        when(mMockIconInjector.getIcon(true /* showX */, 3))
                .thenReturn(mMockShowXDrawable3);
        when(mMockIconInjector.getIcon(true /* showX */, 4))
                .thenReturn(mMockShowXDrawable4);
    }

    @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(false /* concise */)).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);
    }

    @Test
    public void levelChanged_showXWifiRefresh_shouldUpdateLevelIcon() {
        final List<Drawable> iconList = new ArrayList<>();
        when(mMockWifiEntry.shouldShowXLevelIcon()).thenReturn(true);
        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(mMockShowXDrawable0, mMockShowXDrawable1,
                mMockShowXDrawable2, mMockShowXDrawable3, mMockShowXDrawable4, null);
    }

    @Test
    public void notNull_whenGetHelpUriString_shouldSetImageButtonVisible() {
        when(mMockWifiEntry.getHelpUriString()).thenReturn(FAKE_URI_STRING);
        final WifiEntryPreference pref =
                new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
        final LayoutInflater inflater = LayoutInflater.from(mContext);
        final View view = inflater.inflate(pref.getLayoutResource(), new LinearLayout(mContext),
                false);
        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(view);

        pref.onBindViewHolder(holder);

        assertThat(view.findViewById(R.id.icon_button).getVisibility()).isEqualTo(View.VISIBLE);
    }

    @Test
    public void helpButton_whenGetHelpUriStringNotNull_shouldSetCorrectContentDescription() {
        when(mMockWifiEntry.getHelpUriString()).thenReturn(FAKE_URI_STRING);
        final WifiEntryPreference pref =
                new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
        final LayoutInflater inflater = LayoutInflater.from(mContext);
        final View view = inflater.inflate(pref.getLayoutResource(), new LinearLayout(mContext),
                false);
        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(view);

        pref.onBindViewHolder(holder);

        assertThat(view.findViewById(R.id.icon_button).getContentDescription()).isEqualTo(
                mContext.getString(R.string.help_label));
    }

    @Test
    public void subscriptionEntry_shouldSetImageButtonGone() {
        when(mMockWifiEntry.isSubscription()).thenReturn(true);
        final WifiEntryPreference pref =
                new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
        final LayoutInflater inflater = LayoutInflater.from(mContext);
        final View view = inflater.inflate(pref.getLayoutResource(), new LinearLayout(mContext),
                false);
        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(view);

        pref.onBindViewHolder(holder);

        assertThat(view.findViewById(R.id.icon_button).getVisibility()).isEqualTo(View.GONE);
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ android_library {
        "res",
    ],
    static_libs: [
        "WifiTrackerLib",
        "WindowManager-Shell",
        "SystemUIAnimationLib",
        "SystemUIPluginLib",
@@ -143,6 +144,7 @@ android_library {
        "src/**/I*.aidl",
    ],
    static_libs: [
        "WifiTrackerLib",
        "SystemUIAnimationLib",
        "SystemUIPluginLib",
        "SystemUISharedLib",