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

Commit c83da50a authored by Zoey Chen's avatar Zoey Chen
Browse files

[ProviderModel] Add InternetAdapter for Wi-Fi network in internet dialog

    - Set each Wi-Fi entry into recycle view
    - Add InternetAdapterTest for unit test

UX design: https://screenshot.googleplex.com/Bniie5mSwm8XXDg.png
Screenshot: https://screenshot.googleplex.com/9rqobLjwkA2whQh.png

Bug: 187779230
Test: atest InternetAdapterTest
Change-Id: I29d2323698920e60eb0b91a5ae45b101f3cb7d68
parent e0cee245
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
    Copyright (C) 2017 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="24dp"
        android:height="24dp"
        android:tint="?android:attr/colorControlNormal"
        android:viewportWidth="24"
        android:viewportHeight="24">
    <path
        android:fillColor="@android:color/white"
        android:pathData="M18,8h-1V6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2H6c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V10C20,8.9 19.1,8 18,8zM9,6c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2H9V6zM18,20H6V10h12V20zM12,17c1.1,0 2,-0.9 2,-2c0,-1.1 -0.9,-2 -2,-2c-1.1,0 -2,0.9 -2,2C10,16.1 10.9,17 12,17z"/>
</vector>
+99 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ 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.
  -->

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/internet_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <LinearLayout
        android:id="@+id/wifi_list"
        android:layout_width="match_parent"
        android:layout_height="72dp"
        android:layout_gravity="center_vertical|start"
        android:clickable="true"
        android:focusable="true"
        android:background="?android:attr/selectableItemBackground"
        android:orientation="horizontal"
        android:paddingStart="@dimen/settingslib_switchbar_padding_left"
        android:paddingEnd="@dimen/settingslib_switchbar_padding_right">

        <FrameLayout
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:clickable="false"
            android:layout_gravity="center_vertical|start"
            android:layout_marginStart="16dp">
            <ImageView
                android:id="@+id/wifi_icon"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"/>
        </FrameLayout>

        <LinearLayout
            android:layout_weight="3"
            android:id="@+id/wifi_network_layout"
            android:orientation="vertical"
            android:clickable="false"
            android:layout_width="wrap_content"
            android:layout_height="72dp">
            <TextView
                android:id="@+id/wifi_title"
                android:layout_weight="1"
                android:layout_width="wrap_content"
                android:layout_height="0dp"
                android:layout_gravity="center_vertical"
                android:gravity="start|center_vertical"
                android:layout_marginLeft="16dp"
                android:ellipsize="end"
                android:maxLines="1"
                android:textColor="?android:attr/textColorPrimary"
                android:textSize="14sp"
                android:fontFamily="google-sans"/>
            <TextView
                android:id="@+id/wifi_summary"
                android:layout_weight="1"
                android:layout_width="wrap_content"
                android:layout_height="0dp"
                android:layout_gravity="center_vertical"
                android:gravity="start|center_vertical"
                android:layout_marginLeft="16dp"
                android:ellipsize="end"
                android:maxLines="1"
                android:textColor="?android:attr/textColorSecondary"
                android:textSize="14sp"
                android:fontFamily="google-sans"/>
        </LinearLayout>

        <FrameLayout
            android:layout_width="24dp"
            android:layout_height="match_parent"
            android:layout_marginRight="@dimen/settingslib_switchbar_padding_right"
            android:clickable="false"
            android:gravity="center">
            <ImageView
                android:id="@+id/wifi_locked_icon"
                android:layout_width="wrap_content"
                android:layout_gravity="center"
                android:layout_height="wrap_content"/>
        </FrameLayout>

    </LinearLayout>
</LinearLayout>
+26 −0
Original line number Diff line number Diff line
@@ -1560,6 +1560,32 @@
    <dimen name="ongoing_call_chip_icon_text_padding">4dp</dimen>
    <dimen name="ongoing_call_chip_corner_radius">28dp</dimen>

    <!-- Internet panel related dimensions -->
    <dimen name="internet_dialog_list_margin">12dp</dimen>
    <dimen name="internet_dialog_list_max_height">614dp</dimen>

    <!-- Signal icon in internet dialog -->
    <dimen name="signal_strength_icon_size">24dp</dimen>

    <!-- Size of internet dialog -->
    <!-- Size of layout margin -->
    <dimen name="settingslib_switchbar_margin">16dp</dimen>
    <!-- Minimum width of switch -->
    <dimen name="settingslib_min_switch_width">48dp</dimen>
    <!-- Size of layout margin left -->
    <dimen name="settingslib_switchbar_padding_left">20dp</dimen>
    <!-- Size of layout margin right -->
    <dimen name="settingslib_switchbar_padding_right">20dp</dimen>
    <!-- Radius of switch bar -->
    <dimen name="settingslib_switch_bar_radius">24dp</dimen>
    <!-- Margin of switch thumb -->
    <dimen name="settingslib_switch_thumb_margin">4dp</dimen>
    <!-- Size of switch thumb -->
    <dimen name="settingslib_switch_thumb_size">16dp</dimen>
    <!-- Width of switch track -->
    <dimen name="settingslib_switch_track_width">48dp</dimen>
    <!-- Height of switch track -->
    <dimen name="settingslib_switch_track_height">24dp</dimen>
    <!-- Radius of switch track -->
    <dimen name="settingslib_switch_track_radius">31dp</dimen>
</resources>
+228 −0
Original line number Diff line number Diff line
/*
 * 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.systemui.qs.tiles.dialog;

import static com.android.wifitrackerlib.WifiEntry.SECURITY_NONE;
import static com.android.wifitrackerlib.WifiEntry.SECURITY_OWE;

import android.annotation.ColorInt;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.text.Html;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.RecyclerView;

import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.wifitrackerlib.WifiEntry;

import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * Adapter for showing Wi-Fi networks.
 */
public class InternetAdapter extends RecyclerView.Adapter<InternetAdapter.InternetViewHolder> {

    private static final String TAG = "InternetAdapter";
    private static final String ACTION_WIFI_DIALOG = "com.android.settings.WIFI_DIALOG";
    private static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key";
    private static final String EXTRA_CONNECT_FOR_CALLER = "connect_for_caller";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    private final InternetDialogController mInternetDialogController;

    protected View mHolderView;
    protected Context mContext;

    public InternetAdapter(InternetDialogController controller) {
        mInternetDialogController = controller;
    }

    @Override
    public InternetViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
            int viewType) {
        mContext = viewGroup.getContext();
        mHolderView = LayoutInflater.from(mContext).inflate(R.layout.internet_list_item,
                viewGroup, false);
        return new InternetViewHolder(mHolderView, mInternetDialogController);
    }

    @Override
    public void onBindViewHolder(@NonNull InternetViewHolder viewHolder, int position) {
        List<WifiEntry> wifiList = getWifiEntryList();
        if (wifiList != null && wifiList.size() != 0) {
            int count = getItemCount();
            if (wifiList.size() > count) {
                wifiList = getWifiEntryList().subList(0, count - 1);
            }

            if (position < wifiList.size()) {
                viewHolder.onBind(wifiList.get(position));
            }
        } else if (DEBUG) {
            Log.d(TAG, "onBindViewHolder, Wi-Fi entry list = null");
        }
    }

    private List<WifiEntry> getWifiEntryList() {
        if (mInternetDialogController.getWifiEntryList() == null) {
            return null;
        }

        return mInternetDialogController.getWifiEntryList().stream()
                .filter(wifiAp -> wifiAp.getConnectedState()
                        != WifiEntry.CONNECTED_STATE_CONNECTED)
                .limit(getItemCount())
                .collect(Collectors.toList());
    }

    /**
     * The total number of networks (mobile network and entries of Wi-Fi) should be four in
     * {@link InternetDialog}.
     *
     * Airplane mode is ON (mobile network is gone):
     *   Return four Wi-Fi's entries if no connected Wi-Fi.
     *   Return three Wi-Fi's entries if one connected Wi-Fi.
     * Airplane mode is OFF (mobile network is visible):
     *   Return three Wi-Fi's entries if no connected Wi-Fi.
     *   Return two Wi-Fi's entries if one connected Wi-Fi.
     *
     * @return The total number of networks.
     */
    @Override
    public int getItemCount() {
        boolean hasConnectedWifi = mInternetDialogController.getConnectedWifiEntry() != null;
        if (mInternetDialogController.isAirplaneModeEnabled()) {
            return hasConnectedWifi ? 3 : 4;
        } else {
            return hasConnectedWifi ? 2 : 3;
        }
    }

    /**
     * ViewHolder for binding Wi-Fi view.
     */
    static class InternetViewHolder extends RecyclerView.ViewHolder {

        final LinearLayout mContainerLayout;
        final LinearLayout mWifiListLayout;
        final LinearLayout mWifiNetworkLayout;
        final ImageView mWifiIcon;
        final TextView mWifiTitleText;
        final TextView mWifiSummaryText;
        final ImageView mWifiLockedIcon;
        final Context mContext;
        final InternetDialogController mInternetDialogController;

        InternetViewHolder(View view, InternetDialogController internetDialogController) {
            super(view);
            mContext = view.getContext();
            mInternetDialogController = internetDialogController;
            mContainerLayout = view.requireViewById(R.id.internet_container);
            mWifiListLayout = view.requireViewById(R.id.wifi_list);
            mWifiNetworkLayout = view.requireViewById(R.id.wifi_network_layout);
            mWifiIcon = view.requireViewById(R.id.wifi_icon);
            mWifiTitleText = view.requireViewById(R.id.wifi_title);
            mWifiSummaryText = view.requireViewById(R.id.wifi_summary);
            mWifiLockedIcon = view.requireViewById(R.id.wifi_locked_icon);
        }

        void onBind(WifiEntry wifiEntry) {
            int security = wifiEntry.getSecurity();
            try {
                mWifiIcon.setImageDrawable(getWifiDrawable(wifiEntry));
                if (isOpenNetwork(security)) {
                    mWifiLockedIcon.setVisibility(View.GONE);
                } else {
                    mWifiLockedIcon.setVisibility(View.VISIBLE);
                    mWifiLockedIcon.setImageDrawable(
                            mContext.getDrawable(R.drawable.ic_friction_lock_closed));
                }
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }

            setWifiNetworkLayout(wifiEntry.getTitle(),
                    Html.fromHtml(wifiEntry.getSummary(false), Html.FROM_HTML_MODE_LEGACY));

            mWifiListLayout.setOnClickListener(v -> {
                if (!isOpenNetwork(security)) {
                    // Popup Wi-Fi password dialog condition:
                    // 1. The access point is a non-open network.
                    // 2. The Wi-Fi connection is not connected with this access point.
                    final Intent intent = new Intent(ACTION_WIFI_DIALOG);
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
                    intent.putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, wifiEntry.getKey());
                    intent.putExtra(EXTRA_CONNECT_FOR_CALLER, false);
                    mContext.startActivity(intent);
                }
                mInternetDialogController.connect(wifiEntry);
            });
        }

        /** Return true if this is an open network AccessPoint. */
        boolean isOpenNetwork(int security) {
            return security == SECURITY_NONE
                    || security == SECURITY_OWE;
        }

        void setWifiNetworkLayout(CharSequence title, CharSequence summary) {
            mWifiNetworkLayout.setVisibility(View.VISIBLE);
            mWifiTitleText.setText(title);
            if (TextUtils.isEmpty(summary)) {
                mWifiTitleText.setGravity(Gravity.CENTER);
                mWifiSummaryText.setVisibility(View.GONE);
                return;
            } else {
                mWifiTitleText.setGravity(Gravity.BOTTOM);
                mWifiSummaryText.setGravity(Gravity.TOP);
                mWifiSummaryText.setVisibility(View.VISIBLE);
            }
            mWifiSummaryText.setText(summary);
        }

        Drawable getWifiDrawable(WifiEntry wifiEntry) throws Throwable {
            Drawable drawable = mContext.getDrawable(
                    com.android.internal.R.drawable.ic_wifi_signal_0);

            AtomicReference<Drawable> shared = new AtomicReference<>();
            final @ColorInt int tint = Utils.getColorAttrDefaultColor(mContext,
                    android.R.attr.colorControlNormal);
            Drawable signalDrawable = mContext.getDrawable(
                    Utils.getWifiIconResource(wifiEntry.getLevel()));
            signalDrawable.setTint(tint);
            shared.set(signalDrawable);
            drawable = shared.get();
            return drawable;
        }
    }
}
+102 −0
Original line number Diff line number Diff line
package com.android.systemui.qs.tiles.dialog;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import android.testing.AndroidTestingRunner;
import android.view.View;
import android.widget.LinearLayout;

import androidx.test.filters.SmallTest;

import com.android.systemui.SysuiTestCase;
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 java.util.Arrays;

@SmallTest
@RunWith(AndroidTestingRunner.class)
public class InternetAdapterTest extends SysuiTestCase {

    private static final String WIFI_TITLE = "Wi-Fi Title";
    private static final String WIFI_SUMMARY = "Wi-Fi Summary";
    private InternetDialogController mInternetDialogController = mock(
            InternetDialogController.class);
    private InternetAdapter mInternetAdapter;
    private InternetAdapter.InternetViewHolder mViewHolder;
    @Mock
    private WifiEntry mWifiEntry = mock(WifiEntry.class);

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mInternetAdapter = new InternetAdapter(mInternetDialogController);
        mViewHolder = (InternetAdapter.InternetViewHolder) mInternetAdapter
                .onCreateViewHolder(new LinearLayout(mContext), 0);
        when(mWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
        when(mWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
        when(mInternetDialogController.getWifiEntryList()).thenReturn(Arrays.asList(mWifiEntry));
    }

    @Test
    public void getItemCount_withApmOnWifiOnNoConnectedWifi_returnFour() {
        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);

        assertThat(mInternetAdapter.getItemCount()).isEqualTo(4);
    }

    @Test
    public void getItemCount_withApmOnWifiOnHasConnectedWifi_returnThree() {
        when(mWifiEntry.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
        when(mInternetDialogController.getConnectedWifiEntry()).thenReturn(mWifiEntry);
        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);

        assertThat(mInternetAdapter.getItemCount()).isEqualTo(3);
    }

    @Test
    public void getItemCount_withApmOffWifiOnNoConnectedWifi_returnThree() {
        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);

        assertThat(mInternetAdapter.getItemCount()).isEqualTo(3);
    }

    @Test
    public void getItemCount_withApmOffWifiOnHasConnectedWifi_returnTwo() {
        when(mWifiEntry.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
        when(mInternetDialogController.getConnectedWifiEntry()).thenReturn(mWifiEntry);
        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);

        assertThat(mInternetAdapter.getItemCount()).isEqualTo(2);
    }

    @Test
    public void onBindViewHolder_bindWithOpenWifiNetwork_verifyView() {
        when(mWifiEntry.getSecurity()).thenReturn(WifiEntry.SECURITY_NONE);
        mInternetAdapter.onBindViewHolder(mViewHolder, 0);

        assertThat(mViewHolder.mWifiTitleText.getVisibility()).isEqualTo(View.VISIBLE);
        assertThat(mViewHolder.mWifiSummaryText.getVisibility()).isEqualTo(View.VISIBLE);
        assertThat(mViewHolder.mWifiIcon.getVisibility()).isEqualTo(View.VISIBLE);
        assertThat(mViewHolder.mWifiLockedIcon.getVisibility()).isEqualTo(View.GONE);
    }

    @Test
    public void onBindViewHolder_bindWithSecurityWifiNetwork_verifyView() {
        when(mWifiEntry.getSecurity()).thenReturn(WifiEntry.SECURITY_PSK);
        mInternetAdapter.onBindViewHolder(mViewHolder, 0);

        assertThat(mViewHolder.mWifiTitleText.getVisibility()).isEqualTo(View.VISIBLE);
        assertThat(mViewHolder.mWifiSummaryText.getVisibility()).isEqualTo(View.VISIBLE);
        assertThat(mViewHolder.mWifiIcon.getVisibility()).isEqualTo(View.VISIBLE);
        assertThat(mViewHolder.mWifiLockedIcon.getVisibility()).isEqualTo(View.VISIBLE);
    }
}